为什么是tail文件?tr(管道)比多行的 sed 或 perl 快?

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 \"要快得多比其他。为什么?

Ste*_*itt 12

它归结为正在完成的工作量。

您的tail | tr命令最终会执行以下操作:

  • tail
    • 读到换行;
    • 输出剩余的所有内容,而不关心换行符;
  • in tr,read,不关心换行符,并输出除 '"' (固定字符)之外的所有内容。

sed在解释给定的脚本后,您的命令最终会执行以下操作:

  • 读取直到换行,累积输入;
  • 如果这是第一行,删除它;
  • 解释正则表达式后,用空替换所有双引号;
  • 输出处理后的行;
  • 循环直到文件结束。

在解释给定的脚本后,您的 Perl 命令最终会执行以下操作:

  • 读取直到换行,累积输入;
  • 解释正则表达式后,用空替换所有双引号;
  • 如果这不是第一行,则输出处理过的行;
  • 循环直到文件结束。

寻找换行符最终在大量输入上变得昂贵。

  • “您的 Perl|sed 命令最终会执行以下操作” - 您忘记了:解释程序。与工具 `tail` 和 `tr` 的功能相比,这两种语言都非常丰富。 (2认同)

piz*_*ect 7

主要是因为 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}代替。

读完第一行后,您可以非常确定后续的行不再是第一行:无需一遍又一遍地检查。