Подтвердить что ты не робот

Параллельная обработка из командной очереди в Linux (bash, python, ruby ​​... что угодно)

У меня есть список/очередь из 200 команд, которые мне нужно запустить в оболочке на сервере Linux.

Я хочу иметь только 10 запущенных процессов (из очереди). Для выполнения некоторых процессов потребуется несколько секунд, другие процессы потребуют гораздо больше времени.

Когда процесс завершится, я хочу, чтобы следующая команда была "выскочена" из очереди и выполнена.

Есть ли у кого-нибудь код для решения этой проблемы?

Дальнейшая разработка:

Там должно быть 200 работ, которые нужно выполнить, в какой-то очереди. Я хочу, чтобы не более 10 произведений продолжалось сразу. Когда нить заканчивает кусок работы, он должен задать очередь для следующей работы. Если в очереди больше нет работы, поток должен умереть. Когда все потоки скончались, это означает, что все работы были выполнены.

Фактическая проблема, которую я пытаюсь решить, заключается в использовании imapsync для синхронизации 200 почтовых ящиков со старого почтового сервера на новый почтовый сервер. У некоторых пользователей большие почтовые ящики и длительная синхронизация tto, у других очень маленькие почтовые ящики и синхронизация.

4b9b3361

Ответ 1

Я бы предположил, что вы можете сделать это, используя make и команду make -j xx.

Возможно, файл makefile, подобный этому

all : usera userb userc....

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

make -j 10 -f makefile

Ответ 2

В оболочке xargs можно использовать для обработки параллельной команды в очереди. Например, для того, чтобы всегда 3 спать параллельно, спать в течение 1 секунды каждый и выполнять 10 спящих в общей сложности

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

И он будет спать всего 4 секунды. Если у вас есть список имен и вы хотите передать имена выполняемым командам, снова выполняя 3 команды параллельно, сделайте

cat names | xargs -n1 -P3 process_name

Выполняет команду process_name alice, process_name bob и т.д.

Ответ 3

Parallel сделано для этого специально.

cat userlist | parallel imapsync

Одна из красот Parallel по сравнению с другими решениями заключается в том, что она гарантирует, что результат не смешан. Выполнение traceroute в Parallel работает отлично, например:

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

Ответ 4

Для этого вида работы PPSS написано: Параллельная обработка оболочки script. Google для этого имени, и вы его найдете, я не буду ссылаться.

Ответ 5

GNU make (и, возможно, другие реализации) имеет аргумент -j, который определяет, сколько заданий он будет запускать сразу. Когда задание завершится, make запустит еще один.

Ответ 6

Хорошо, если они в значительной степени независимы друг от друга, я бы подумал с точки зрения:

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

Обратите внимание, что тест хвоста в основном цикле означает, что если "очередь выполнения заданий" имеет место, когда цикл while повторяется, это предотвращает преждевременное завершение цикла. Я думаю, что логика звучит.

Я вижу, как сделать это на C довольно легко - это не будет так сложно в Perl, и (и поэтому не слишком сложно на других языках сценариев - Python, Ruby, Tcl и т.д.). Я совсем не уверен, что хочу сделать это в оболочке - команда wait в оболочке ожидает, что все дети завершатся, а не для того, чтобы какой-либо дочерний объект завершился.

Ответ 7

В python вы можете попробовать:

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()

Непроверено...

(конечно, сам python является однопоточным. Однако вы все равно получите преимущество нескольких потоков в ожидании ввода-вывода.)

Ответ 8

Если вы собираетесь использовать Python, я рекомендую использовать Twisted.

В частности Twisted Runner.

Ответ 10

Python модуль многопроцессорности, похоже, будет хорошо соответствовать вашей проблеме. Это пакет высокого уровня, который поддерживает потоки по процессу.

Ответ 11

Простая функция в zsh для параллелизации заданий не более чем с 4 подоболочками с использованием файлов блокировки в /tmp.

Единственной нетривиальной частью являются флаги glob в первом тесте:

  • #q: включить подшивку имени файла в тесте
  • [4]: возвращает только 4-й результат
  • N: игнорировать ошибку при пустом результате

Это должно быть легко преобразовать в posix, хотя было бы немного более подробным.

Не забывайте избегать кавычек в заданиях с помощью \".

#!/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

Ответ 12

Вы можете уточнить, что вы подразумеваете под параллелью? Похоже, вам нужно реализовать некоторую блокировку в очереди, чтобы ваши записи не были выбраны дважды, и т.д., А команды запускаются только один раз.

Большинство систем очередей обманывают - они просто пишут гигантский список дел, затем выбирают, например. десять предметов, работать с ними и выбирать следующие десять предметов. Там нет распараллеливания.

Если вы предоставите более подробную информацию, я уверен, что мы можем вам помочь.