Pergunta

Sinto-me frequentemente escrever simples para loops para executar uma operação para muitos arquivos, por exemplo:

for i in `find . | grep ".xml$"`; do bzip2 $i; done

Parece um pouco deprimente que na minha máquina de 4-core apenas um núcleo está sendo usado .. há uma maneira fácil eu posso adicionar paralelismo à minha shell script?

EDIT: Para introduzir um pouco mais contexto para os meus problemas, desculpe, eu não era mais claro para começar com

!

Muitas vezes deseja executar scripts simples (ish), tais como enredo um gráfico, compactar ou descompactar, ou executar algum programa, em conjuntos de dados de tamanho razoável (geralmente entre 100 e 10.000). Os scripts que eu uso para resolver tais problemas parecido com o descrito acima, mas pode ter um comando diferente, ou mesmo uma sequência de comandos para executar.

Por exemplo, só agora eu estou correndo:

for i in `find . | grep ".xml.bz2$"`; do find_graph -build_graph $i.graph $i; done

Assim, meus problemas não são de forma bzip específico! (Embora bzip paralelo faz olhar fresco, eu pretendo usá-lo no futuro).

Foi útil?

Solução

Se você tivesse que resolver o problema hoje você provavelmente usaria uma ferramenta como o GNU paralela (a menos que haja uma ferramenta paralelizado especializada para a sua tarefa como pbzip2):

find . | grep ".xml$" | parallel bzip2

Para saber mais:

Outras dicas

Solução : Use xargs para executar em paralelo (! Não se esqueça da opção -n)

find -name \*.xml -print0 | xargs -0 -n 1 -P 3 bzip2

Este programa perl adapta às suas necessidades razoavelmente bem, você teria apenas que fazer isso:

runN -n 4 bzip2 `find . | grep ".xml$"`

GNU make tem um recurso interessante paralelismo (eg. -J 5) que iria trabalhar no seu caso. Criar um Makefile

%.xml.bz2 : %.xml


all: $(patsubt %.xml,%xml.bz2,$(shell find . -name '*.xml') ) 

, em seguida, fazer um

nice make -j 5

substituir '5' com um número, provavelmente 1 mais do que o número de CPUs. Você pode querer fazer 'agradável' este apenas no caso de alguém quiser usar a máquina enquanto você está nele.

A resposta para a pergunta geral é difícil, porque depende dos detalhes das coisas que você está paralelização. Por outro lado, para este fim específico, você deve usar pbzip2 vez de bzip2 simples (as chances são de que pbzip2 já está instalado ou, pelo menos nos repositórios ou sua distro). Veja aqui para mais detalhes: http://compression.ca/pbzip2/

I encontrar este tipo de contraproducente operação. O motivo é a mais processos acessar o disco ao mesmo tempo, quanto maior o tempo de leitura / gravação vai assim as extremidades resultado final em um longo tempo. O gargalo aqui não vai ser um problema de CPU, não importa quantos núcleos que você tem.

Você não já realizado um simples dois grandes cópias de arquivos ao mesmo tempo na mesma unidade HD? I é geralmente mais rápida para copiar um e depois o outro.

Eu sei que esta tarefa envolve algum poder de CPU (bzip2 é exigente método de compressão), mas tente medir primeira carga da CPU antes de ir a "desafiar" caminho que todos os técnicos tendem a escolher com muito mais frequência do que o necessário.

Eu fiz algo parecido com isto para a festança. O truque paralelo make é provavelmente muito mais rápido para one-offs, mas aqui é a seção de código principal para implementar algo parecido com isso em bash, você terá que modificá-lo para seus propósitos embora:

#!/bin/bash

# Replace NNN with the number of loops you want to run through
# and CMD with the command you want to parallel-ize.

set -m

nodes=`grep processor /proc/cpuinfo | wc -l`
job=($(yes 0 | head -n $nodes | tr '\n' ' '))

isin()
{
  local v=$1

  shift 1
  while (( $# > 0 ))
  do
    if [ $v = $1 ]; then return 0; fi
    shift 1
  done
  return 1
}

dowait()
{
  while true
  do
    nj=( $(jobs -p) )
    if (( ${#nj[@]} < nodes ))
    then
      for (( o=0; o<nodes; o++ ))
      do
        if ! isin ${job[$o]} ${nj[*]}; then let job[o]=0; fi
      done
      return;
    fi
    sleep 1
  done
}

let x=0
while (( x < NNN ))
do
  for (( o=0; o<nodes; o++ ))
  do
    if (( job[o] == 0 )); then break; fi
  done

  if (( o == nodes )); then
    dowait;
    continue;
  fi

  CMD &
  let job[o]=$!

  let x++
done

wait

Eu acho que você podia para o seguinte

for i in `find . | grep ".xml$"`; do bzip2 $i&; done

Mas isso cisão no entanto muitos processos que você tenha arquivos instantaneamente e não é um ideal como apenas correr quatro processos ao mesmo tempo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top