如何仅在列表中的目标上使用 makefile 中的 .NOTPARALLEL?
How can I use .NOTPARALLEL in makefile only on targets from list?
我使用make
来执行一个复杂的计算,其中涉及多次运行不同的程序,其计算结果相互依赖。在这些运行中,有几次高度 optimized/vectorized/multi-threaded 程序的执行和几次单线程 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 program
fast_target/%
可以存入变量,但不能手工枚举(有几十个)
我想按顺序计算所有 fast_target/%
但并行计算其他目标。怎么做?
P.S。这道题有点类似于How can I use .NOTPARALLEL in makefile only on specific targets?.
一种可能的方法是在配方中的文件级别使用同步。它当然不是最好的(因为它仍然会消耗 make
的工作),但不应该通过 运行ning n 多线程程序使系统过载.
示例生成文件:
$ 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 的列表,并且对于每个目标,它将定义对前一个目标的依赖关系。这将导致 运行 的严格顺序,因此其中 none 将是 运行 并行。此外,它不会阻止 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
方法不会出现这种情况。
我使用make
来执行一个复杂的计算,其中涉及多次运行不同的程序,其计算结果相互依赖。在这些运行中,有几次高度 optimized/vectorized/multi-threaded 程序的执行和几次单线程 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 program
fast_target/%
可以存入变量,但不能手工枚举(有几十个)
我想按顺序计算所有 fast_target/%
但并行计算其他目标。怎么做?
P.S。这道题有点类似于How can I use .NOTPARALLEL in makefile only on specific targets?.
一种可能的方法是在配方中的文件级别使用同步。它当然不是最好的(因为它仍然会消耗 make
的工作),但不应该通过 运行ning n 多线程程序使系统过载.
示例生成文件:
$ 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 的列表,并且对于每个目标,它将定义对前一个目标的依赖关系。这将导致 运行 的严格顺序,因此其中 none 将是 运行 并行。此外,它不会阻止 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
方法不会出现这种情况。