使用make并行执行独立任务

时间:2010-11-05 13:14:05

标签: unix shell makefile buildfarm

我有一堆我想要并行执行的命令。命令几乎相同。它们可能需要大约相同的时间,并且可以完全独立运行。他们可能看起来像:

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

我可以在shell脚本中并行启动所有这些,但系统会尝试加载超过严格必要的负载以保持CPU忙(每个任务占用一个核心的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 个答案:

答案 0 :(得分:4)

这是更多可移植的shell代码,不依赖于大括号扩展:

  

LOGS:= $(shell seq 1 1024)

注意使用:=来定义一个更有效的变量:简单扩展的“味道”。

答案 1 :(得分:3)

请参阅pattern rules

另一种方式,如果这是您需要make的唯一原因,则使用-n的{​​{1}}和-P选项。

答案 2 :(得分:3)

首先是简单的部分。正如Roman Cheplyaka指出的那样,模式规则非常有用:

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

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

棘手的部分是创建该列表LOGS。 Make不是很擅长处理数字。最好的方法可能是调用shell。 (您可能必须为shell调整此脚本 - shell脚本不是我最强的主题。)

NUM_LOGS = 4096

LOGS = $(shell for ((i=1 ; i<=$(NUM_LOGS) ; ++i)) ;  do  echo log.$$i ; done)

答案 3 :(得分:3)

xargs -P是执行此操作的“标准”方式。 注意,根据磁盘I / O,您可能希望限制为主轴而不是核心。 如果您确实要限制核心,请记录最近coreutils中的新nproc命令。

答案 4 :(得分:2)

使用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