Fra*_*anò 9 performance sed perl text-processing
我有一个大约一百万行的文件,如下所示:
"ID" "1" "2"
"00000687" 0 1
"00000421" 1 0
"00000421" 1 0
"00000421" 1 0
Run Code Online (Sandbox Code Playgroud)
最后一行重复了超过一百万次。从这个问题中获得灵感,我尝试了一些建议的解决方案,看看哪个更快。我原以为只有一个进程的解决方案会比那些有管道的解决方案更快,因为它们只使用一个进程。但这些是我的测试结果:
tail -n +2 file.txt | tr -d \"
$ time tail -n +2 file.txt | tr -d \" 1> /dev/null
real 0m0,032s
user 0m0,020s
sys 0m0,028s
Run Code Online (Sandbox Code Playgroud)sed '1d;s/"//g' file.txt
$ time sed '1d;s/"//g' file.txt 1> /dev/null
real 0m0,410s
user 0m0,399s
sys 0m0,011s
Run Code Online (Sandbox Code Playgroud)perl -ne ' { s/"//g; print if $. > 1 }' file.txt
$ time perl -ne ' { s/"//g; print if $. > 1 }' file.txt 1> /dev/null
real 0m0,379s
user 0m0,367s
sys 0m0,013s
Run Code Online (Sandbox Code Playgroud)我多次重复测试,我总是得到相似的数字。正如你所看到的,tail -n +2 file.txt | tr -d \"
是要快得多比其他。为什么?
Ste*_*itt 12
它归结为正在完成的工作量。
您的tail | tr
命令最终会执行以下操作:
tail
:
tr
,read,不关心换行符,并输出除 '"' (固定字符)之外的所有内容。sed
在解释给定的脚本后,您的命令最终会执行以下操作:
在解释给定的脚本后,您的 Perl 命令最终会执行以下操作:
寻找换行符最终在大量输入上变得昂贵。
主要是因为 perl 和 sed 分别处理每一行。
如果让 perl 用更大的块处理输入,并稍微简化一下(请参阅注释),则可以使其更快——但没有任何地方比 tr 快:
time perl -ne ' { s/"//g; print if $. > 1 }' file.txt 1> /dev/null
real 0m0.617s
user 0m0.612s
sys 0m0.005s
time perl -pe 'BEGIN{<>;$/=\40960} s/"//g' file.txt >/dev/null
real 0m0.186s
user 0m0.177s
sys 0m0.009s
time tail -n +2 file.txt | tr -d \" 1> /dev/null
real 0m0.033s
user 0m0.031s
sys 0m0.023s
Run Code Online (Sandbox Code Playgroud)
注意:不要使用perl -ne '... if $. > 1'
或awk 'NR == 1 { ... } /foo/ { ... }'
。
使用BEGIN{<>}
和BEGIN{getline}
代替。
读完第一行后,您可以非常确定后续的行不再是第一行:无需一遍又一遍地检查。