Параллельный запуск программ с использованием xargs

86

В настоящее время у меня есть текущий сценарий.

#!/bin/bash
# script.sh

for i in {0..99}; do
   script-to-run.sh input/ output/ $i
done

Я хочу запустить его параллельно, используя xargs. я пытался

script.sh | xargs -P8

Но выполнение описанного выше выполняется только один раз. Не повезло и с -n8. Добавление & в конце строки, которая будет выполняться в сценарии цикла for, приведет к попытке запустить сценарий одновременно 99 раз. Как мне выполнить цикл только 8 за раз, всего до 100?

Оливье
источник
Это то, что я изначально хотел сделать, но мне пришлось прибегнуть к xargs, потому что я работаю в Windows. Мне не удалось запустить GNU Parallel в Windows,
Оливье,
Этот скрипт вызывает сам себя или вы просто перепутали имена, когда спросили здесь?
Этан Рейснер
Извините, он должен вызвать другой скрипт. Я исправлю это
Оливье
Здесь актуален ответ на stackoverflow.com/questions/3321738/… .
Этан Рейснер

Ответы:

129

На xargsстранице руководства :

Эта страница руководства документирует GNU-версию xargs. xargs считывает элементы из стандартного ввода, разделенные пробелами (которые могут быть защищены двойными или одинарными кавычками или обратной косой чертой) или новой строкой, и выполняет команду (по умолчанию / bin / echo) один или несколько раз с любыми начальными аргументами, за которыми следуют по элементам, считанным из стандартного ввода. Пустые строки в стандартном вводе игнорируются.

Это означает, что для вашего примера xargsожидается ожидание и сбор всех выходных данных вашего скрипта, а затем выполнение echo <that output>. Не совсем то, что вам нужно.

-nАргумент , сколько элементов из входных данных для использования с каждой командой , которая не запускаемой (ничего, само собой, о параллельности здесь).

Чтобы делать то, что вы хотите, xargsвам нужно будет сделать что-то вроде этого (непроверено):

printf %s\\n {0..99} | xargs -n 1 -P 8 script-to-run.sh input/ output/

Что ломается вот так.

  • printf %s\\n {0..99}- Печатать по одному числу в каждой строке от 0до99 .
  • Бежать xargs
    • принимая самое большее одного аргумента для каждой командной строки запуска
    • и запускать до восьми процессов одновременно
Этан Рейснер
источник
8
На самом деле вам не нужно помещать аргументы в отдельные строки; xargs разбивает слова. Так echo {0..99} |что будет работать так же хорошо. <<<{0..99}не работает; хотя <<<wordзадокументировано как слово, расширяющее фигурные скобки, этого не происходит ни в одной из доступных мне версий bash.
rici
1
@rici Похоже на ошибку документации, тем более, что в документации для Here Documents не упоминается расширение скобок (и этого не происходит и в быстром тесте), хотя они также не упоминают расширение тильды (чего не происходит для <<но делает для <<<этого *shrug*). Расширения, которые случаются и не встречаются здесь, в документах и ​​здесь, строках, на мой взгляд, немного странны.
Этан Рейснер
1
Как можно разделить результаты из разных прогонов, например, с помощью новой строки?
nirvana-msu 08
4
Демо: time head -12 <(yes "1") | xargs -n1 -P4 sleepбудет работать 12 sleep 1команд, 4 параллельно. Команда займет 3 секунды.
Walter A
66

С GNU Parallel вы бы сделали:

parallel script-to-run.sh input/ output/ {} ::: {0..99}

Добавьте, -P8если вы не хотите запускать одно задание на каждое ядро ​​ЦП.

Напротив, xargsон будет делать Правильную вещь, даже если входные данные содержат пробел, 'или "(хотя здесь не тот случай). Он также следит за тем, чтобы выходные данные разных заданий не смешивались вместе, поэтому, если вы используете выход, вы Гарантированно, что вы не получите пол-очереди с двух разных работ.

GNU Parallel - это общий распараллеливатель, который упрощает параллельное выполнение заданий на одном компьютере или на нескольких компьютерах, к которым у вас есть доступ по ssh.

Если у вас есть 32 разных задания, которые вы хотите запустить на 4 процессорах, простой способ распараллеливания - запустить 8 заданий на каждом процессоре:

Простое планирование

GNU Parallel вместо этого порождает новый процесс, когда один из них завершается, сохраняя активными процессоры и тем самым экономя время:

Параллельное планирование GNU

Установка

Если GNU Parallel не входит в комплект поставки вашего дистрибутива, вы можете выполнить персональную установку, для которой не требуется root-доступ. Это можно сделать за 10 секунд следующим образом:

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 67bd7bc7dc20aff99eb8f1266574dadb
12345678 67bd7bc7 dc20aff9 9eb8f126 6574dadb
$ md5sum install.sh | grep b7a15cdbb07fb6e11b0338577bc1780f
b7a15cdb b07fb6e1 1b033857 7bc1780f
$ sha512sum install.sh | grep 186000b62b66969d7506ca4f885e0c80e02a22444
6f25960b d4b90cf6 ba5b76de c1acdf39 f3d24249 72930394 a4164351 93a7668d
21ff9839 6f920be5 186000b6 2b66969d 7506ca4f 885e0c80 e02a2244 40e8a43f
$ bash install.sh

Для других вариантов установки см. Http://git.savannah.gnu.org/cgit/parallel.git/tree/README.

Учить больше

См. Другие примеры: http://www.gnu.org/software/parallel/man.html

Посмотрите вступительные видеоролики: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Изучите руководство: http://www.gnu.org/software/parallel/parallel_tutorial.html

Подпишитесь на список рассылки, чтобы получить поддержку: https://lists.gnu.org/mailman/listinfo/parallel

Оле Танге
источник
19
Это не отвечает на вопрос и не указывает, почему xargs не может добиться того же.
张 实 唯
8
Голосуйте против, потому что xarg для меня работает точно так, как показано на втором рисунке.
noonex 07
3
@noonex Знаете ли вы, что не все используют ту версию xargs, которую вы используете, и что -P присутствует не во всех версиях xargs?
Ole Tange
20
Возможно, не все знают, что этот ответ предоставлен автором GNU parallel.
izkeros
1
Проголосовали против из-за явной рекламы программного обеспечения, которое не работает должным образом, как описано, при первых попытках, из-за интерактивного запроса, который сбивает с толку большинство скриптов.
Даниэль Соричетти,