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

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

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

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

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

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

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

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

  • Выполнение многострочных операторов Python в однострочной командной строке
  • Запуск команды оболочки из Python и захват вывода
  • Почему бы просто не использовать `shell = True` в subprocess.Popen в Python?
  • Почему subprocess.Popen () с shell = True работает по-разному в Linux и Windows?
  • Модуль Python для shellquote / unshellquote?
  • Выполнение командной строки в другой папке
  • 12 Solutions collect form web for “Параллельная обработка из командной очереди в Linux (bash, python, ruby ​​… безотносительно)”

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

    Возможно, такой файл makefile

     all : usera userb userc.... usera: imapsync usera userb: imapsync userb .... 

    make -j 10 -f makefile

    В оболочке 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 и т.

    Для этой цели параллелируется исключительно.

     cat userlist | parallel imapsync 

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

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

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

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

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

     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 в оболочке ждет, когда все дети закончатся, а не для того, чтобы какой-нибудь ребенок закончил.

    В 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, eg # 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 является однопоточным. Однако вы все равно получите преимущество нескольких потоков в ожидании ввода-вывода).

    https://savannah.gnu.org/projects/parallel (gnu parallel) и pssh могут помочь.

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

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

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

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

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

    • #q : включить #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 

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

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

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

    Python - лучший язык программирования в мире.