Минимальная «очередь задач» со стандартными инструментами Linux для использования многоядерных процессоров - PullRequest
7 голосов
/ 07 мая 2009

Каков наилучший / самый простой способ построения системы минимальной очереди задач для Linux с использованием bash и распространенных инструментов?

У меня есть файл с 9'000 строк, каждая строка имеет командную строку bash, команды полностью независимы.

command 1 > Logs/1.log
command 2 > Logs/2.log
command 3 > Logs/3.log
...

В моей коробке более одного ядра, и я хочу одновременно выполнять X задач. Я искал в Интернете хороший способ сделать это. Очевидно, у многих людей есть эта проблема, но пока ни у кого нет хорошего решения.

Было бы неплохо, если бы решение имело следующие функции:

  • может интерпретировать более одной команды (например, command; command)
  • может интерпретировать перенаправления потока на линии (например, ls > /tmp/ls.txt)
  • использует только общие инструменты Linux

Бонусные баллы, если он работает на других Unix-клонах без слишком экзотических требований.

Ответы [ 9 ]

14 голосов
/ 07 мая 2009

Можете ли вы преобразовать свой список команд в Makefile? Если это так, вы можете просто запустить "make -j X".

9 голосов
/ 11 июня 2010

GNU Parallel http://www.gnu.org/software/parallel/ - более общий инструмент для распараллеливания, чем PPSS.

Если runfile содержит:

command 1 > Logs/1.log
command 2 > Logs/2.log
command 3 > Logs/3.log

вы можете сделать:

cat runfile | parallel -j+0

, которая будет запускать одну команду на ядро ​​ЦП.

Если ваши команды такие же простые, как и выше, вам даже не нужен runfile, но вы можете сделать:

seq 1 3 | parallel -j+0 'command {} > Logs/{}.log'

Если у вас есть больше компьютеров для обработки, вы можете посмотреть опции --sshlogin и --trc для GNU Parallel.

0 голосов
/ 22 марта 2015

Очередь задач + Параллельное + Динамическое добавление

Используя FIFO, этот скрипт сам обрабатывает очередь. Таким образом, вы можете добавлять команды в очередь на лету (когда очередь уже запущена).

Использование: ./queue Команда [количество детей] [Имя очереди]

Пример, с 1 потоком:

./queue "sleep 5; echo ONE"
./queue "echo TWO"

Выход:

ONE
TWO

Пример, с 2-мя потоками:

./queue "sleep 5; echo ONE" 2
./queue "echo TWO"

Выход:

TWO
ONE

Пример, с 2 очередями:

./queue "sleep 5; echo ONE queue1" 1 queue1
./queue "sleep 3; echo ONE queue2" 1 queue2

Выход:

ONE queue2
ONE queue1

Сценарий (сохраните его как «очередь» и chmod + x очередь):


    #!/bin/bash

    #Print usage
    [[ $# -eq 0 ]] && echo Usage: $0 Command [# of children] [Queue name] && exit

    #Param 1 - Command to execute
    COMMAND="$1"

    #Param 2 - Number of childs in parallel
    MAXCHILD=1
    [[ $# -gt 1 ]] && MAXCHILD="$2"

    #Param 3 - File to be used as FIFO
    FIFO="/tmp/defaultqueue"
    [[ $# -gt 2 ]] && FIFO="$3"

    #Number of seconds to keep the runner active when unused
    TIMEOUT=5

    runner(){
      #Associate file descriptor 3 to the FIFO
      exec 3"$FIFO"

      while read -u 3 -t $TIMEOUT line; do
        #max child check
        while [ `jobs | grep Running | wc -l` -ge "$MAXCHILD" ]; do
          sleep 1
        done

        #exec in backgroud
        (eval "$line")&
      done
      rm $FIFO
    }

    writer(){
      #fork if the runner is not running
      lsof $FIFO >/dev/null || ($0 "QueueRunner" "$MAXCHILD" "$FIFO" &)

      #send the command to the runner
      echo "$COMMAND" > $FIFO
    }

    #Create the FIFO file
    [[ -e "$FIFO" ]] || mkfifo "$FIFO"

    #Start the runner if in the runner fork, else put the command in the queue
    [[ "$COMMAND" == "QueueRunner" ]] && runner || writer

0 голосов
/ 04 ноября 2014

Вы могли видеть мою очередь задач, написанную на bash: https://github.com/pavelpat/yastq

0 голосов
/ 07 сентября 2009

Это особый случай, но если вы пытаетесь обработать набор файлов и создать другой набор выходных файлов, вы можете запустить #cores число процессов и проверить, существует ли выходной файл перед его обработкой. Пример ниже преобразует каталог файлов .m4b в файлы .mp3:

Просто запустите эту команду столько раз, сколько у вас ядер:

ls * m4b | при чтении f; сделать тест -f $ {f% m4b} mp3 || mencoder -of rawaudio "$ f" -oac mp3lame -ovc copy -o $ {f% m4b} mp3; сделано &

0 голосов
/ 09 мая 2009

Вы можете использовать команду xargs , ее - max-procs делает то, что вы хотите. Например, решение Чарли Мартина делается с помощью xargs:

tr '\012' '\000' <mycommands.sh |xargs --null --max-procs=$X bash -c

подробности:

  • X - количество процессов макс. Например: X = 15. --max-procs творит магию
  • первый tr здесь для завершения строк нулевыми байтами для опции xargs --null, чтобы перенаправление кавычек и т. Д. Не расширялось неправильно
  • bash -c запускает команду

Я протестировал его с помощью этого файла mycommands.sh, например:

date
date "+%Y-%m-%d" >"The Date".txt
wc -c <'The Date'.txt >'The Count'.txt
0 голосов
/ 07 мая 2009

Подобное удовольствие от распределенных вычислений - скрипт Mapreduce Bash:

http://blog.last.fm/2009/04/06/mapreduce-bash-script

И спасибо, что указали на ppss!

0 голосов
/ 07 мая 2009

Ну, это все равно забавный вопрос.

Вот что я бы сделал, если предположить bash (1) конечно.

  • выясните, сколько из этих команд может быть полезно одновременно запущено. Это будет не просто количество ядер; Многие команды будут приостановлены для ввода-вывода и тому подобное. Например, позвоните по этому номеру N. N=15.
  • установить обработчик сигнала прерывания для сигнала SIGCHLD, который происходит, когда дочерний процесс завершается. trap signalHandler SIGCHLD
  • cat ваш список команд в трубу
  • написать цикл, который читает stdin и выполняет команды одну за другой, уменьшая счетчик. Когда счетчик равен 0, он wait с.
  • ваш обработчик сигнала, который работает на SIGCHLD, увеличивает этот счетчик.

Итак, теперь он запускает первые N команды, а затем ждет. Когда первый дочерний элемент завершается, возвращается ожидание, он читает другую строку, запускает новую команду и ждет снова.

Теперь, это случай, когда многие задания заканчиваются близко друг к другу. Я подозреваю, Вы можете уйти с более простой версией:

 N=15
 COUNT=N
 cat mycommands.sh | 
 while read cmd 
 do
   eval $cmd &
   if $((count-- == 0))
   then
       wait
   fi
 od

Теперь эта команда запустит первые 15 команд, а затем выполнит остальные по одной, когда какая-то команда завершится.

0 голосов
/ 07 мая 2009

Хорошо, после публикации вопроса я нашел следующий проект, который выглядит многообещающе: ppss .

Редактировать: Не совсем то, что я хочу, PPSS ориентирован на обработку "всех файлов в каталоге A".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...