Mik*_*uke 6 performance awk gawk
我有一个 8400 万行的 XML,正在 Red Hat Linux 中使用“gawk”进行处理。(好吧,有些人会建议使用其他工具而不是 GAWK,但我的 XML 没有多行标记或任何其他特性,使 GAWK 不是这项工作的良好选择。)
我关心的是性能。
我最初的 AWK 脚本是这样的:
# Test_1.awk
BEGIN {FS = "<|:|=";}
{
if ($3 == "SubNetwork id")
{
# do something
}
}
END {
# print something
}
Run Code Online (Sandbox Code Playgroud)
每行进行一次 8400 万次字符串比较。
我注意到“SubNetwork id”仅在该行中有 4 个字段 (NF=4) 时出现,因此我更改了脚本以减少字符串比较:
# Test_2.awk
BEGIN {FS = "<|:|=";}
{
if (NF == 4)
{
if ($3 == "SubNetwork id")
{
# do something
}
}
}
END {
# print something
}
Run Code Online (Sandbox Code Playgroud)
我运行它,发现我检查了 'NF == 4' 8400 万次(显而易见),而'$3 == "SubNetwork id"' 仅检查了 300 万次。太好了,我减少了字符串比较的次数,我一直认为字符串比较比简单的整数比较更耗时(NF 是整数,对吧?)。
当我测试这两个脚本的性能时,我感到惊讶。大多数时候 Test_1 比 Test_2 快。我多次运行它们来考虑可能使用 CPU 时间的其他进程,但总的来说,我的测试是在 CPU 或多或少“空闲”时运行的。
我的大脑告诉我,8400万次整数比较加上300万次字符串比较一定比8400万次字符串比较快,但显然我的推理有问题。
我的 XML 看起来像这样:
<?xml version="1.0" encoding="UTF-8"?>
<ConfigDataFile xmlns:un="specific.xsd" xmlns:xn="generic.xsd">
<configData dnPrefix="Undefined">
<xn:SubNetwork id="ROOT_1">
<xn:SubNetwork id="ROOT_2">
<xn:attributes>
...
</xn:attributes>
</xn:SubNetwork>
<xn:SubNetwork id="ID_1">
....
</xn:SubNetwork>
<xn:SubNetwork id="ID_2">
.....
</xn:SubNetwork>
</xn:SubNetwork>
</configData>
</ConfigDataFile>
Run Code Online (Sandbox Code Playgroud)
任何有助于理解此性能问题的帮助将不胜感激。
提前致谢。
下面是一个简单的测试。第一行将 10,000,000 行“abc d”输出到文件 a 中。awk是 GNU Awk 4.1.3
[~] yes 'a b c d' | h -10000000 > a
[~] time awk '{if(NF==5)print("a")}' a
2.344u 0.012s 0:02.36 99.5% 0+0k 0+0io 0pf+0w
[~] time awk '{if(NF==5)print("a")}' a
2.364u 0.008s 0:02.37 99.5% 0+0k 0+0io 0pf+0w
[~] time awk '{if($4=="Hahaha")print("a")}' a
2.876u 0.024s 0:02.90 99.6% 0+0k 0+0io 0pf+0w
[~] time awk '{if($4=="Hahaha")print("a")}' a
2.880u 0.020s 0:02.90 100.0% 0+0k 0+0io 0pf+0w
[~] time awk '{if($1=="Hahaha")print("a")}' a
2.540u 0.020s 0:02.56 100.0% 0+0k 0+0io 0pf+0w
[~] time awk '{if($1=="Hahaha")print("a")}' a
2.404u 0.004s 0:02.41 99.5% 0+0k 0+0io 0pf+0w
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,检查 $1 比检查 $4 更快,因为在前一种情况下,AWK 只需要解析该行直到第一个单词。如果您仅检查 NF,AWK 只会计算单词数,在我的情况下甚至更快,但在您的情况下,计算单词数可能比解析输入行到第三个单词慢。
最后,我们可以这样加速 AWK:
[~] time awk '/Hahaha/{if($4=="Hahaha")print("a")}' a
1.376u 0.020s 0:01.40 99.2% 0+0k 0+0io 0pf+0w
[~] time awk '/Hahaha/{if($4=="Hahaha")print("a")}' a
1.372u 0.028s 0:01.40 99.2% 0+0k 0+0io 0pf+0w
Run Code Online (Sandbox Code Playgroud)
因为/Hahaha/不需要任何解析。
如果您/SubNetwork id/在 之前添加{,可能会加快速度。
如果您只处理带有“SuNetwork id”的行并忽略所有其他行,您可能需要这样做
grep 'SubNetwork id' your_input_file | awk -f prog.awk
Run Code Online (Sandbox Code Playgroud)
它会大大加快速度,因为 grep 比 awk 快得多。
最后,另一种加速 awk 的方法是使用 mawk,它比 gawk 快得多。不幸的是,有时它会产生与 gawk 不同的结果,因此应该始终对其进行测试。
| 归档时间: |
|
| 查看次数: |
5675 次 |
| 最近记录: |