Минимальная “Очередь задач” со стандартными инструментами Linux для использования многоядерного процессора

StackOverflow https://stackoverflow.com/questions/832253

  •  06-07-2019
  •  | 
  •  

Вопрос

Каков наилучший / самый простой способ создать минимальную систему очередей задач для 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-клонах без слишком экзотических требований.

Это было полезно?

Решение

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

Другие советы

GNU Параллельный 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.

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

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

Ну, в любом случае, это своего рода забавный вопрос.

Вот что бы я сделал, предполагая удар (1) конечно.

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

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

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

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

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

Аналогичной забавой для распределенных вычислений является скрипт Mapreduce Bash:

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

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

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

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

Подробные сведения:

  • 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

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

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

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

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

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

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

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

Пример, с 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

Скрипт (сохраните его как "queue" и chmod +x queue):

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top