首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AWK/GAWK性能

AWK/GAWK性能
EN

Stack Overflow用户
提问于 2017-04-20 16:19:59
回答 3查看 3.8K关注 0票数 5

我有一个8400万行的XML,我在Red Hat Linux中用“gawk”处理它。(好吧,有些人会建议使用其他工具,而不是GAWK,但是我的XML没有多行标记或任何其他使GAWK不适合这项工作的特性。)

我关心的是性能。

我的初始AWK脚本是这样的:

代码语言:javascript
复制
# Test_1.awk
BEGIN {FS = "<|:|=";}
{
if ($3 == "SubNetwork id")
    {
    # do something
    }
}
END {
# print something
}

这就进行了8400万次字符串比较,每行一次。

我注意到只有在行(NF=4)中有4个字段时才会出现"SubNetwork id“,所以我更改了脚本以进行更少的字符串比较:

代码语言:javascript
复制
# Test_2.awk
BEGIN {FS = "<|:|=";}
{
if (NF == 4)
    {
    if ($3 == "SubNetwork id")
        {
        # do something
        }
    }
}
END {
# print something
}

我运行它,发现我检查了'NF == 4‘8400万次(很明显)和'$3 == "SubNetwork id"’只有300万次。很好,我减少了字符串比较的次数,我一直认为这比简单的整数比较更耗时(NF是整数,对吧?)。

当我测试这两个脚本的性能时,我大吃一惊。在大多数情况下,Test_1比Test_2快,我会多次运行它们来计算其他可能正在使用CPU时间的进程,但总的来说,我的测试都是在CPU或多或少处于“空闲”状态时运行的。

我的大脑告诉我,8400万个整数比较加上300万个字符串比较肯定比8400万个字符串比较快,但很明显,我的推理出了问题。

我的XML如下所示:

代码语言:javascript
复制
<?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>

如果能帮助我们理解这个性能问题,我们将不胜感激。

提前谢谢。

EN

回答 3

Stack Overflow用户

发布于 2017-04-20 23:28:53

我做了更多的测试:

1-生成包含某些数据的大文件

代码语言:javascript
复制
yes 'SomeSampleText SomeOtherText 33 1970 YetAnotherText 777 abc 1 AndSomeMore' | head -12000000 > SomeData.txt

分隔符是空格!

2-多次运行这6个测试,并计算每个测试的平均时间。我在3台不同的机器( Red Hat Linux Enterprise 4)上做到了这一点。

代码语言:javascript
复制
time gawk 'BEGIN {a = 0;} {if ($5 == "YetAnotherText") a ++;} END {print "a: " a;}' SomeData.txt
time gawk 'BEGIN {a = 0;} {if ($0 ~ /YetAnotherText/) a ++;} END {print "a: " a;}' SomeData.txt
time gawk 'BEGIN {a = 0;} /YetAnotherText/ {a ++;} END {print "a: " a;}' SomeData.txt
time gawk 'BEGIN {a = 0;} {if (NF == 9) a ++;} END {print "a: " a;}' SomeData.txt
time gawk 'BEGIN {a = 0;} {if ($1 == "SomeSampleText") a ++;} END {print "a: " a;}' SomeData.txt
time gawk 'BEGIN {a = 0;} {if ($9 == "AndSomeMore") a ++;} END {print "a: " a;}' SomeData.txt

3-我得到了这些结果(数字是秒)

代码语言:javascript
复制
-- Machine 1
10.35
39.39
38.87
10.40
7.72
12.26

-- Machine 2
8.50
32.43
31.83
9.10
6.54
9.91

-- Machine 3
12.35
13.55
12.90
14.40
9.43
14.93

在测试2和3中搜索pattern /YetAnotherText/看起来非常慢。除了机器3。

4-生成另一个具有不同分隔符的数据的大文件

代码语言:javascript
复制
yes "<SomeSampleText:SomeOtherText=33>1970<YetAnotherText:777=abc>1<AndSomeMore>" | head -12000000 > SomeData2.txt

5-运行6个测试,更改FS

代码语言:javascript
复制
time gawk 'BEGIN {FS = "<|:|=";} {if ($5 == "YetAnotherText") a ++;} END {print "a: " a;}' SomeData2.txt
time gawk 'BEGIN {FS = "<|:|=";} {if ($0 ~ /YetAnotherText/) a ++;} END {print "a: " a;}' SomeData2.txt
time gawk 'BEGIN {FS = "<|:|=";} /YetAnotherText/ {a ++;} END {print "a: " a;}' SomeData2.txt
time gawk 'BEGIN {FS = "<|:|=";} {if (NF == 8) a ++;} END {print "a: " a;}' SomeData2.txt
time gawk 'BEGIN {FS = "<|:|=";} {if ($2 == "SomeSampleText") a ++;} END {print "a: " a;}' SomeData2.txt
time gawk 'BEGIN {FS = "<|:|=";} {if ($8 == "AndSomeMore>") a ++;} END {print "a: " a;}' SomeData2.txt

6-我得到了这些结果(我只在机器3上做了,抱歉)

代码语言:javascript
复制
66.17
33.11
32.16
76.77
37.17
77.20

我的结论(也可以查看@user31264的评论):

当有一个简单的分隔符时,解析和拆分到字段似乎更快,而不是几个分隔符。获取模式比获取模式更快,其中N

  • 在某些情况下,在整行中搜索/ $N /比比较模式“==”更快,特别是当N不是行的第一个字段时

  • 获取NF可能会很慢,因为该行必须被解析并计算字段,如果有多个分隔符

,则会更慢

票数 3
EN

Stack Overflow用户

发布于 2017-04-20 16:55:21

下面是一个简单的测试。第一行将10,000,000行"a b c d“输出到文件a。awk是GNU Awk 4.1.3

代码语言:javascript
复制
[~] 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

正如您所看到的,检查$1比检查$4更快,因为在前一种情况下,AWK只需要解析直到第一个单词的行。如果你只检查NF,AWK只计算单词,这在我的例子中甚至更快,但在你的例子中,计算单词可能比解析输入行到第三个单词慢。

最后,我们可以像这样加速AWK:

代码语言:javascript
复制
[~] 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

因为/Hahaha/不需要任何解析。

如果在{之前添加/SubNetwork id/,可能会加快速度。

如果只处理具有"SuNetwork id“的行,而忽略所有其他行,则可能需要这样做

代码语言:javascript
复制
grep 'SubNetwork id' your_input_file | awk -f prog.awk

这将大大加快速度,因为grep比awk快得多。

最后,另一种提高awk速度的方法是使用mawk,它比gawk快得多。不幸的是,有时它会产生与gawk不同的结果,因此应该始终对其进行测试。

票数 1
EN

Stack Overflow用户

发布于 2017-04-20 17:52:04

另一个简单的测试

文件是整个样本的3.000.000行副本。结果是运行3次后的代表性时间(针对缓存和其他操作系统影响)

代码语言:javascript
复制
# time awk 'BEGIN{FS="[<:=]"}NF>=4{a++}END{print a+0}' YourFile
780100
real    0m1.89s user    0m1.74s sys     0m0.01s

# time awk 'BEGIN{FS="<|:|="}NF>=4{a++}END{print a+0}' YourFile
780100
real    0m2.00s user    0m1.91s sys     0m0.02s

# time awk 'BEGIN{FS="<|:|="}NF>=4&&/:SubNetwork/{a++}END{print a+0}' YourFile
780100
real    0m3.09s user    0m2.93s sys     0m0.02s

# time awk 'BEGIN{FS=":SubNetwork"}NF>=2{a++}END{print a+0}' YourFile
1560200
real    0m1.32s user    0m1.27s sys     0m0.02s

# time awk '/:SubNetwork/{a++}END{print a}' YourFile
1560200
real    0m3.23s user    0m3.06s sys     0m0.02s

展示如果你使用:SubNetwork作为字段分隔符,它是最快的。

现在,对于下面的操作,您可能需要通过诸如FS="<|:|=";$1=$1"";$0=$0""; ... your action ...; FS=":SubNetwork"之类的东西拆分或重新分隔该字段

作为预过滤的额外测试

代码语言:javascript
复制
# time awk '$1 == "<xn:SubNetwork" || $1 == "<xn:Attributes" {a++}END{print a+0}' YourFile
780100
real    0m1.29s user    0m1.20s sys     0m0.03s
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43513975

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档