如何在Makefile中拆分输入文件列表,实现高效并行调用程序?
纯Make实现输入文件分组批量处理
以下是完全基于Make内置能力(仅使用shell基础整数运算,未调用bash/awk等外部脚本工具)的解决方案,可将输入文件均匀拆分为指定数量的组,配合make -j实现高效并行处理:
# 配置参数:设置并行处理的进程数和输入文件列表 NUM_GROUPS := 8 IN_FILES := f1.in f2.in f3.in f4.in f5.in f6.in f7.in f8.in f9.in f10.in f11.in f12.in # 计算总文件数量 TOTAL_FILES := $(words $(IN_FILES)) # 计算每组基础文件数和余数:前REM个组每组多1个文件,保证分组均匀 QUOT := $(shell echo $$(( $(TOTAL_FILES) / $(NUM_GROUPS) ))) REM := $(shell echo $$(( $(TOTAL_FILES) % $(NUM_GROUPS) ))) # 定义生成单组文件列表的函数 define DEFINE_GROUP # 计算当前组的文件起始/结束位置 ifeq ($(1),1) START := 1 else ifeq ($(1),$(shell echo $$(( $(REM) + 1 )))) START := $(shell echo $$(( $(REM) * ($(QUOT) + 1) + 1 ))) else ifneq ($(shell echo $$(( $(1) <= $(REM) ))),0) START := $(shell echo $$(( ($(1) - 1) * ($(QUOT) + 1) + 1 ))) else START := $(shell echo $$(( $(REM) * ($(QUOT) + 1) + ($(1) - $(REM) - 1) * $(QUOT) + 1 ))) endif ifeq ($(shell echo $$(( $(1) <= $(REM) ))),0) END := $(shell echo $$(( $(START) + $(QUOT) - 1 ))) else END := $(shell echo $$(( $(START) + $(QUOT) ))) endif # 截取对应范围的文件列表 GROUP_$(1) := $(wordlist $(START),$(END),$(IN_FILES)) endef # 循环生成所有组的文件列表定义 $(foreach n,$(shell seq 1 $(NUM_GROUPS)),$(eval $(call DEFINE_GROUP,$(n)))) # 生成所有分组处理目标 GROUP_TARGETS := $(foreach n,$(shell seq 1 $(NUM_GROUPS)),group_$(n).out) # 默认目标 all: $(GROUP_TARGETS) # 分组处理规则:单次调用Program处理整组文件 group_%.out: Program $^ > $@ # 为每个分组目标绑定对应文件依赖 $(foreach n,$(shell seq 1 $(NUM_GROUPS)),$(eval group_$(n).out: $(GROUP_$(n))))
方案说明
- 参数配置:修改
NUM_GROUPS设置并行进程数(比如你需要的8次),IN_FILES填入所有输入文件。 - 均匀分组:通过整数运算计算每组文件数量,当总文件数无法被分组数整除时,前N个组会多1个文件,保证各组数量尽可能均衡。
- 并行执行:执行
make -j$(NUM_GROUPS)即可启动指定数量的并行进程,每个进程一次性处理一组文件,彻底避免频繁启动Program的开销。
如果要求完全不依赖任何shell调用,纯Make实现整数运算会非常繁琐(Make无原生整数运算支持),上述方案是平衡简洁性与需求的最优解。
内容的提问来源于stack exchange,提问作者dash-o
相关产品推荐
相关产品推荐

