Использование make для параллельного выполнения независимых задач - PullRequest
4 голосов
/ 05 ноября 2010

У меня есть несколько команд, которые я хотел бы выполнять параллельно. Команды почти идентичны. Можно ожидать, что они займут примерно одинаковое время и могут работать совершенно независимо. Они могут выглядеть так:

command -n 1 > log.1
command -n 2 > log.2
command -n 3 > log.3
...
command -n 4096 > log.4096

Я мог бы запустить их все параллельно в сценарии оболочки, но система попыталась бы загрузить больше, чем строго необходимо, чтобы загружать ЦП (каждая задача занимает 100% одного ядра до завершения). Это заставит диск треснуть и сделает все это медленнее, чем менее жадный подход к выполнению.

Наилучшим подходом, вероятно, является продолжение выполнения n задач, где n - количество доступных ядер.

Я стремлюсь не изобретать велосипед. Эта проблема уже была решена в программе Unix make (при использовании с опцией -j n). Мне было интересно, возможно ли было написать общие правила Makefile для вышеупомянутого, чтобы избежать Makefile линейного размера, который выглядел бы так:

all: log.1 log.2 ...
log.1:
        command -n 1 > log.1
log.2:
        command -n 2 > log.2
...

Если лучшим решением является не использование make, а другая программа / утилита, я открыт для этого, пока зависимости разумны (make был очень хорош в этом отношении).

Ответы [ 5 ]

4 голосов
/ 09 ноября 2010

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

LOGS: = $ (shell seq 1 1024)

Обратите внимание на использование:= определить более эффективную переменную: просто расширенный «аромат».

3 голосов
/ 05 ноября 2010

Сначала легкая часть.Как отмечает Роман Чепляка, шаблонные правила очень полезны:

LOGS = log.1 log.2 ... log.4096
all: $(LOGS)

log.%:
    command -n $* > log.$*

Сложная часть создает этот список, LOGSМарка не очень хороша в обработке чисел.Наилучший способ - это, вероятно, вызвать оболочку.(Возможно, вам придется настроить этот сценарий для вашей оболочки - сценарии оболочки не моя самая сильная тема.)

NUM_LOGS = 4096

LOGS = $(shell for ((i=1 ; i<=$(NUM_LOGS) ; ++i)) ;  do  echo log.$$i ; done)
3 голосов
/ 05 ноября 2010

xargs -P - это «стандартный» способ сделать это. Обратите внимание, что в зависимости от дискового ввода-вывода вы можете ограничить количество шпинделей, а не ядер. Если вы хотите ограничиться ядрами, обратите внимание на новую команду nproc в недавних coreutils.

3 голосов
/ 05 ноября 2010

См. шаблон правил

Другой способ, если это единственная причина, по которой вам нужно make, - это использовать -n и -P опции xargs.

2 голосов
/ 06 ноября 2013

В GNU Parallel вы написали бы:

parallel command -n {} ">" log.{} ::: {1..4096}

10 секундная установка:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

Узнать больше: http://www.gnu.org/software/parallel/parallel_tutorial.html https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

...