gawk 3.1.5(Linux)中for循环性能问题技术求助
优化gawk 3.1.5中for循环遍历数组的性能问题
我之前处理大文件时也碰到过类似的gawk性能瓶颈,一点点代码写法的差异就能带来天差地别的耗时变化。先梳理下你遇到的情况:
你用这段gawk代码处理80万行的文本文件:
BEGIN { TagOpen["Req"] = "<S:Envelope" TagClose["Req"] = "</S:Envelope" TagOpen["Resp"] = "<SOAP-ENV:Envelope" TagClose["Resp"]= "</SOAP-ENV:Envelope" } { if ( NR % 10000 == 0 ) print NR } { for (i in TagOpen) { if ( match($0, TagOpen[i]) ) printf "Open [%s]\n", i if ( match($0, TagClose[i]) ) printf "Close [%s]\n", i } }
最终耗时:
real 0m56.84s
user 0m56.02s
问题根源
gawk 3.1.5里的for (i in array)遍历存在不小的额外开销——哪怕你的数组只有2个元素,每一行都要执行一次数组遍历、元素取值的操作,80万行下来,这个开销就被无限放大了。虽然逻辑上用循环处理数组没问题,但当前场景下完全可以通过更直接的写法避免这种不必要的损耗。
优化方案
既然你的标签类型是固定的(只有Req和Resp两种),完全不需要用数组遍历,直接显式判断每个标签的匹配情况就行:
BEGIN { req_open = "<S:Envelope" req_close = "</S:Envelope" resp_open = "<SOAP-ENV:Envelope" resp_close = "</SOAP-ENV:Envelope" } { if (NR % 10000 == 0) print NR if (match($0, req_open)) printf "Open [Req]\n" if (match($0, req_close)) printf "Close [Req]\n" if (match($0, resp_open)) printf "Open [Resp]\n" if (match($0, resp_close)) printf "Close [Resp]\n" }
效果预期
这种写法去掉了数组遍历的额外开销,直接做4次match判断,处理80万行的耗时应该能降到几秒级别,性能提升非常明显。如果后续需要增加标签类型,再考虑用数组循环也不迟,但当前场景下显式判断是最优解。
内容的提问来源于stack exchange,提问作者Gianluca Trombetta
相关产品推荐
相关产品推荐

