Makefile 多核并行制造,而不是;螺纹;执行?

Makefile 多核并行制造,而不是;螺纹;执行?,makefile,parallel-processing,Makefile,Parallel Processing,我有一个Makefile来执行一个大致如下的测试套件: %.diff.png: %.test.png echo '$*: Comparing with good PNG.' %.test.png: %.pdf echo '$*: Converting PDF to PNG.' %.pdf: %.tex echo '$*: Generating PDF output.' 当我使用多作业make运行这些测试时(make-j2 test),测试以“线程化”顺序执行: ...

我有一个Makefile来执行一个大致如下的测试套件:

%.diff.png: %.test.png echo '$*: Comparing with good PNG.' %.test.png: %.pdf echo '$*: Converting PDF to PNG.' %.pdf: %.tex echo '$*: Generating PDF output.' 当我使用多作业make运行这些测试时(
make-j2 test
),测试以“线程化”顺序执行:

... umtest202a:生成PDF输出。 umtest202b:生成PDF输出。 ... umtest202a:将PDF转换为PNG。 umtest202b:将PDF转换为PNG。 ... umtest202a:与良好的PNG进行比较。 umtest202b:与良好的PNG进行比较。 ... 也许你能看到问题所在;在发现测试是否失败之前,它已经为每个其他测试运行了所有PDF生成和PNG转换


是否有一种方法来组织测试,以便即使在使用多个作业运行时,测试也会在继续下一个测试之前一直运行到完成?或者这是一个更好的
制作
的任务吗?

我读了一些关于
-j
标志的文章,我认为问题是这为独立规则启动了新的工作。每个图像的作业都是独立的,因此每个目标的第一个依赖项将像您看到的那样运行

我认为这里的主要问题是,这个任务本质上是串行的,也就是说,每个目标的依赖项必须依次运行。因此,在每个目标中,您没有办法在这种粒度级别上利用多道程序设计


由于
make
似乎没有按照您想要的顺序处理依赖项,因此支持并行测试的单元测试框架可能更合适。我通过谷歌搜索知道其中有几个退出,但我不能推荐什么时候退出,因为我没有使用过任何语言,也不确定您使用的是哪种语言。

除非明确指定了目标的执行顺序,
make
以任意顺序执行它们——并行和非并行模式。此订单会经历
make
的内部算法,在您的情况下会产生令人不快的结果

解决方案是促使对测试进行显式排序

在makefile中,我假设存在一个未公开的“source”变量,该变量包含要测试的目标列表(隐式目标依赖于这些目标)。同时,该变量的立即展开也会产生正确的结果

假设变量如下所示:

list=file1 file2 file3 ... fileN
然后,为了解决问题,生成以下依赖项就足够了:

file2: file1
file3: file2 
...
fileN: fileN-1
run_tests: fileN
我们应该如何生成它?让我们在
列表
变量获取其值后编写一个foreach eval循环

len=$(words $(list))
$(foreach t,                                                  \
   $(join                                                     \ 
      $(addsuffix : ,$(wordlist 2,$(len),$(list)) run_tests), \
      $(list)                                                 \
   )                                                          \
   , $(eval $(t))                                             \
)
这将生成makefile的一部分,就像C预处理器(或者更准确地说,LISP宏)一样。它的工作原理如下:对于由
join
ing(将第一个列表的每个元素与第二个列表的相应元素连接起来)形成的列表中的每个项目
t
,列表
file2 file3。。。fileN run_tests
,在每个元素中添加后缀
(从而形成
file2:file3:…fileN:run_tests:
),源列表
file1 file2。。。文件
;-对于具有连接元素的列表中的每个此类项
t
,将其作为makefile源的一部分进行评估,从而按照上述规则进行操作


现在您只需调用run_tests目标,它就会一个接一个地运行。

突然,我想到了另一个主意

%.diff.png:
    $(MAKE) $*.test.png
    echo '$*: Comparing with good PNG.'

这解决了所有问题,只是测试可能没有按正确的顺序调用(但在实践中,它们很可能会进行得很顺利)。

您的“每个目标的依赖项必须按顺序运行”一针见血。不过,我想我的问题不清楚;无论我指定了多少个作业,都会生成整个PDF集,然后全部转换为PNG,然后全部进行正确性测试。奇怪的是,DEP会以这种方式处理。我已经用一些不同的建议更新了我的答案。我明白你在这里说的,但我认为它需要更多的工作:这种方法将完全串行化处理,否定任何可以并行实现的收益。所以我想我想要
test3:test1
test4:test2
test5:test3
,等等。(对并行执行的数量进行硬编码,但没关系。)就在两天前,在我的工作中,我遇到了同样的问题。我推断,如果你想混合顺序和并行,最好不要使用
make
。假设您采用了
test3:test1
方案,并且
test1
需要1小时才能完成,而所有其他测试总共需要1小时。然后,使用这种方案,总执行时间将延长50%(使用2个并行作业)。
len=$(words $(list))
$(foreach t,                                                  \
   $(join                                                     \ 
      $(addsuffix : ,$(wordlist 2,$(len),$(list)) run_tests), \
      $(list)                                                 \
   )                                                          \
   , $(eval $(t))                                             \
)
%.diff.png:
    $(MAKE) $*.test.png
    echo '$*: Comparing with good PNG.'