我使用make来执行一个复杂的计算,它涉及到几个不同程序的运行,其计算结果相互依赖。其中包括对高度优化/矢量化/多线程程序的几次执行,以及对单线程python脚本的多次执行。因此,Makefile有以下部分:
slow_target/%: fast_target/%
python $<
#run of the unparalleled single-threaded python program
fast_target/%: #some dependencies for each %
#run of the multi-core paralleled programfast_target/%可以存储在变量中,但不能手工枚举(其中有几十个)。
我想按顺序计算所有fast_target/%,但其他目标并行计算。该怎么做呢?
这个问题有点类似于How can I use .NOTPARALLEL in makefile only on specific targets?。
发布于 2020-05-19 21:48:50
一种可能的方法是在食谱中的文件级别上使用同步。它当然不是最好的(因为它仍然会消耗make的工作),但是不应该通过运行n个多线程程序来使系统超载。
示例Makefile:
$ cat Makefile
all: $(foreach number,1 2 3 4 5 6 7 8 9 10,$(addsuffix /$(number),slow_target fast_target))
slow_target/%:
@echo $@
@python3 -c 'import time; time.sleep(5)'
fast_target/%:
@( \
flock 9 || exit 1; \
echo $@; \
python3 -c 'import time; time.sleep(5)' \
) 9> fast_target.lock输出:
$ make -j8 | ts
May 19 23:45:06 slow_target/1
May 19 23:45:06 slow_target/2
May 19 23:45:06 fast_target/1
May 19 23:45:06 slow_target/3
May 19 23:45:06 slow_target/4
May 19 23:45:11 fast_target/2
May 19 23:45:11 slow_target/5
May 19 23:45:11 slow_target/6
May 19 23:45:11 slow_target/7
May 19 23:45:16 fast_target/3
May 19 23:45:16 slow_target/8
May 19 23:45:16 slow_target/9
May 19 23:45:21 fast_target/4
May 19 23:45:21 slow_target/10
May 19 23:45:26 fast_target/5
May 19 23:45:31 fast_target/6
May 19 23:45:36 fast_target/7
May 19 23:45:41 fast_target/8
May 19 23:45:46 fast_target/9
May 19 23:45:51 fast_target/10注意,slow_targets是并行启动的,但每次只启动一个fast_target。
编辑
flock获取给定文件或给定文件描述符的锁。默认情况下,锁是独占的,这意味着只有一个flock调用可以继续,所有其他调用都会阻塞,直到锁被释放。因此,如果并行调用多个目标,则只有一个flock将继续执行,而其他目标将等待锁释放。
菜谱中的语句是基于flock的手册。它打开给定块的fast_target.lock文件上的文件描述符9。开始时,flock获取该描述符的独占锁(因此是fast_target.lock文件),当描述符关闭时(即重定向块结束时),该描述符将自动释放。当这种情况发生时,其他flock之一将继续进行,实际上只允许执行一个fast_target配方。
编辑2
如果已知并始终执行所有fast_targets,则可以按顺序动态调度它们,如下所示:
$ cat Makefile2
SLOW_TARGETS := $(addprefix slow_target/,1 2 3 4 5 6 7 8 9 10)
FAST_TARGETS := $(addprefix fast_target/,1 2 3 4 5 6 7 8 9 10)
all: $(SLOW_TARGETS) $(FAST_TARGETS)
slow_target/%:
@echo $@
@python3 -c 'import time; time.sleep(5)'
fast_target/%:
@echo $@: $^
@python3 -c 'import time; time.sleep(5)'
$(foreach target,$(FAST_TARGETS), \
$(eval evaluated_targets += $(target)) \
$(eval next_target := $(word 2,$(wordlist $(words $(evaluated_targets)),$(words $(FAST_TARGETS)),$(FAST_TARGETS)))) \
$(eval $(if $(next_target),$(next_target): $(target))) \
)这将迭代已知的fast_targets列表,对于每个目标,它将定义对前一个目标的依赖关系。这将导致严格的序列运行,因此它们都不会并行运行。此外,它不会阻止make作业,因此执行器将可用于其他目标,而不是在flock上被阻塞。
$ make -f Makefile2 -j8 | ts
May 20 22:38:35 slow_target/1
May 20 22:38:35 slow_target/2
May 20 22:38:35 slow_target/3
May 20 22:38:35 slow_target/4
May 20 22:38:35 slow_target/5
May 20 22:38:35 slow_target/6
May 20 22:38:35 slow_target/7
May 20 22:38:35 slow_target/8
May 20 22:38:40 slow_target/9
May 20 22:38:40 slow_target/10
May 20 22:38:40 fast_target/1:
May 20 22:38:45 fast_target/2: fast_target/1
May 20 22:38:51 fast_target/3: fast_target/2
May 20 22:38:56 fast_target/4: fast_target/3
May 20 22:39:01 fast_target/5: fast_target/4
May 20 22:39:06 fast_target/6: fast_target/5
May 20 22:39:11 fast_target/7: fast_target/6
May 20 22:39:16 fast_target/8: fast_target/7
May 20 22:39:21 fast_target/9: fast_target/8
May 20 22:39:26 fast_target/10: fast_target/9注意,由于依赖关系,不需要进一步的逻辑操作,就不可能运行例如fast_target/10,因为前面的所有目标也将被运行。flock方法的情况并非如此。
https://stackoverflow.com/questions/61893540
复制相似问题