Pergunta

Eu tenho uma lista / fila de 200 comandos que eu preciso para executar em um shell em um servidor Linux.

Eu só quero ter um máximo de 10 processos em execução (da fila) de uma só vez. Alguns processos vai demorar alguns segundos para completar outros processos, levará muito mais tempo.

Quando um processo termina Quero que o próximo comando a ser "bateu" a partir da fila e executado.

Alguém tem código para resolver este problema?

Além disso elaboração:

Há 200 peças de trabalho que precisam ser feitas, em uma fila de algum tipo. Quero ter no máximo 10 peças de trabalho acontecendo ao mesmo tempo. Quando um segmento termina um pedaço de trabalho que deve pedir a fila para o próximo pedaço de trabalho. Se não há mais trabalho na fila, o segmento deve morrer. Quando todos os tópicos morreram isso significa todo o trabalho foi feito.

O problema real que eu estou tentando resolver está usando imapsync para sincronizar 200 caixas de correio de um servidor de correio antigo para um novo servidor de correio. Alguns usuários têm grandes caixas de correio e levar um longo tempo tto sync, outros têm muito pequenas caixas de correio e sincronização rapidamente.

Foi útil?

Solução

Eu imagino que você poderia fazer isso usando o make eo make -j comando xx.

Talvez um makefile como este

all : usera userb userc....

usera:
       imapsync usera
userb:
       imapsync userb
....

fazer -j 10 -f makefile

Outras dicas

No shell, xargs pode ser usado para a fila de processamento do comando paralelo. Por exemplo, para ter sempre 3 dorme em paralelo, de dormir durante 1 segundo cada, e a execução de tarefas em 10 dorme total de

echo {1..10} | xargs -d ' ' -n1 -P3 sh -c 'sleep 1s' _

E seria dormir por 4 segundos no total. Se você tem uma lista de nomes, e quer passar os nomes para comandos executados, novamente executar 3 comandos em paralelo, faça

cat names | xargs -n1 -P3 process_name

Será que executar o process_name alice comando, process_name bob e assim por diante.

Paralelo é feita exatcly para esta finalidade.

cat userlist | parallel imapsync

Uma das belezas da Parallel comparado a outras soluções é que ele torna-se de saída é não misturado. Fazendo traceroute em Parallel fina funciona por exemplo:

(echo foss.org.my; echo www.debian.org; echo www.freenetproject.org) | parallel traceroute

Para este tipo de trabalho PPSS está escrito: shell script processamento paralelo. Google para este nome e você vai encontrá-lo, eu não vou linkspam.

GNU make (e talvez outras implementações também) tem o argumento -j, que governa quantos empregos serão executados ao mesmo tempo. Quando A completa de trabalho, make irá iniciar um outro.

Bem, se eles são em grande parte independentes um do outro, eu acho que em termos de:

Initialize an array of jobs pending (queue, ...) - 200 entries
Initialize an array of jobs running - empty

while (jobs still pending and queue of jobs running still has space)
    take a job off the pending queue
    launch it in background
    if (queue of jobs running is full)
        wait for a job to finish
        remove from jobs running queue
while (queue of jobs is not empty)
    wait for job to finish
    remove from jobs running queue

Note que o teste de cauda nos principais meios de circuito que se os 'empregos correndo fila' tem espaço quando o loop while itera - prevenção interrupção prematura do loop. Eu acho que a lógica é boa.

Eu posso ver como fazer isso em C bastante facilidade - não seria tão difícil em Perl, ou (e, portanto, não muito difícil nas outras linguagens de script - Python, Ruby, Tcl, etc). Eu não tenho certeza de que eu gostaria de fazê-lo com casca - o comando wait em espera shell para todas as crianças para terminar, em vez de por algum filho terminar

.

Em Python, você poderia tentar:

import Queue, os, threading

# synchronised queue
queue = Queue.Queue(0)    # 0 means no maximum size

# do stuff to initialise queue with strings
# representing os commands
queue.put('sleep 10')
queue.put('echo Sleeping..')
# etc
# or use python to generate commands, e.g.
# for username in ['joe', 'bob', 'fred']:
#    queue.put('imapsync %s' % username)

def go():
  while True:
    try:
      # False here means no blocking: raise exception if queue empty
      command = queue.get(False)
      # Run command.  python also has subprocess module which is more
      # featureful but I am not very familiar with it.
      # os.system is easy :-)
      os.system(command)
    except Queue.Empty:
      return

for i in range(10):   # change this to run more/fewer threads
  threading.Thread(target=go).start()

Não experimentado ...

(claro, o próprio Python é single-threaded. Você deve ainda obter o benefício de vários segmentos em termos de espera de IO, embora.)

Se você estiver indo para usar Python, eu recomendo usar torcida para isso.

torcida Runner .

https://savannah.gnu.org/projects/parallel (gnu paralelo) e phsss pode ajudar.

Python do multiprocessamento módulo parece caber o seu problema muito bem. É um pacote de alto nível que suporta segmentação por processo.

função simples em zsh para paralelizar postos de trabalho em não mais de 4 subshells, usando arquivos de bloqueio em / tmp.

A única parte não trivial são as bandeiras glob no primeiro teste:

  • #q: permitir filename englobamento em um teste
  • [4]: retorna somente o quarto resultado
  • N: ignorar erro no resultado vazio

Deve ser fácil para convertê-lo para posix, apesar de que seria um pouco mais detalhada.

Não se esqueça de escapar qualquer cotações nos empregos com \".

#!/bin/zsh

setopt extendedglob

para() {
    lock=/tmp/para_$$_$((paracnt++))
    # sleep as long as the 4th lock file exists
    until [[ -z /tmp/para_$$_*(#q[4]N) ]] { sleep 0.1 }
    # Launch the job in a subshell
    ( touch $lock ; eval $* ; rm $lock ) &
    # Wait for subshell start and lock creation
    until [[ -f $lock ]] { sleep 0.001 }
}

para "print A0; sleep 1; print Z0"
para "print A1; sleep 2; print Z1"
para "print A2; sleep 3; print Z2"
para "print A3; sleep 4; print Z3"
para "print A4; sleep 3; print Z4"
para "print A5; sleep 2; print Z5"

# wait for all subshells to terminate
wait

Você pode elaborar o que você quer dizer com em paralelo ? Parece que você precisa para implementar algum tipo de bloqueio na fila para as entradas não são selecionados duas vezes, etc e os comandos executado apenas uma vez.

A maioria dos sistemas de fila enganar - eles simplesmente escrever um gigante lista de tarefas, selecione, por exemplo, itens de dez, o trabalho deles, e selecionar os itens seguintes dez. Não há paralelização.

Se você fornecer mais alguns detalhes, eu estou certo de que podemos ajudá-lo.

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