如何提升处理30GB大文件的for循环中grep命令的执行效率
优化方案
你当前的性能瓶颈来自于2万次循环中每次都全量扫描30GB的主文件、以及重复扫描2个映射CSV文件,重复IO开销占了99%以上的执行时间,多进程只能提升CPU利用率,解决不了反复读取大文件的磁盘IO瓶颈,这是跑一整天的核心原因。
优化思路是彻底砍掉重复IO,只扫1次主文件、2次映射CSV就能完成全部处理,不需要安装任何额外工具,仅用系统自带的awk、fgrep即可实现。
具体实现步骤
步骤1:预生成所有SKU的处理规则
只扫描2次小体积的映射CSV,提前把所有SKU对应的处理类型、替换目标、输出文件规则全部预计算好,避免循环中反复查询CSV:
# 预生成SKU处理规则,仅需执行1次 awk -F',' ' # 先加载SS类型映射表 NR == FNR { ss_type[$1] = $NF next } # 再加载CF映射表,生成每个SKU的处理规则 { # 处理列1的SKU规则 if (!rule[$1]) { if (ss_type[$1] == "U") { rule[$1] = "UUU " $1 } else if (ss_type[$1] == "C") { rule[$1] = "CUF " $2 } } # 处理列2的SKU规则 if (!rule[$2]) { parent_sku = $1 if (ss_type[parent_sku] == "U") { rule[$2] = "UCU " parent_sku } else if (ss_type[parent_sku] == "C") { rule[$2] = "CCC " $2 } } } # 补全不在映射表中的SKU默认规则 END { while ((getline sku < "'"${outFile}_skusOnly"'") > 0) { if (!rule[sku]) { rule[sku] = "as_is " sku } print sku " " rule[sku] } } ' ${dir}/Univ_SS_FCST_Lvl.csv ${dir}/Univ_CF_Map.csv > ${outFile}_sku_rules.tmp
步骤2:单次扫描30GB主文件完成全部处理
用fgrep多模式匹配一次性捞出所有包含目标SKU的行,再用awk按预生成的规则直接处理并输出到对应文件,全程仅扫描1次主文件:
# 单次扫描主文件完成所有处理 LC_ALL=C fgrep -h -f ${outFile}_skusOnly ${outFile} | awk -v out_prefix="${outFile}_sorted_sku_mapped_" ' # 加载预生成的规则 NR == FNR { sku = $1 type = $2 replace_sku = $3 rule[sku] = type " " replace_sku next } # 逐行处理匹配结果 { for (sku in rule) { if (index($0, sku) != 0) { split(rule[sku], r, " ") type = r[1] replace_sku = r[2] # 按规则替换SKU if (type == "CUF" || type == "UCU") { gsub(sku, replace_sku, $0) } # 写入对应输出文件 print $0 >> (out_prefix type "_" sku) # 确认每行仅匹配一个SKU的话可加break,避免重复处理 break } } } ' ${outFile}_sku_rules.tmp - # 清理临时文件 rm -f ${outFile}_sku_rules.tmp
额外优化点
- 若确认主文件每行仅包含一个目标SKU,可提前对规则中的SKU按长度倒序排序,优先匹配长SKU避免短SKU误匹配
- 如服务器内存足够,可将主文件拆分为数个大小相近的分片,用多进程分别处理每个分片,最后合并同类型的输出文件,可进一步提升速度
- 不需要保留原有的多进程逻辑,单进程执行上述代码即可比原方案快10~100倍,正常30GB文件几十分钟即可跑完
内容的提问来源于stack exchange,提问作者Vinri Eclar
相关产品推荐
相关产品推荐

