如何仅在列表中的目标上使用 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 方法不会出现这种情况。