首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么尾部文件\ tr (管道)比带许多行的sed或perl更快?

为什么尾部文件\ tr (管道)比带许多行的sed或perl更快?
EN

Unix & Linux用户
提问于 2020-05-21 13:38:40
回答 4查看 1.6K关注 0票数 10

我有一个大约一百万行的文件,如下所示:

代码语言:javascript
复制
"ID" "1" "2"
"00000687" 0 1
"00000421" 1 0
"00000421" 1 0
"00000421" 1 0

最后一行重复了100多万次。从这个问题获得灵感,我尝试了一些建议的解决方案,看看哪一个更快。我原以为只有一个进程的解决方案会比有管道的解决方案更快,因为它们只使用一个进程。但这是我的测试结果:

  • tail -n +2 file.txt | tr -d \" $ time -n +2 file.txt \ tr -d \“1> /dev/空实0m0,032s用户0m0,020 sys 0m0,028s
  • sed '1d;s/"//g' file.txt $ time sed '1d;s/"//g‘file.txt 1> /dev/null实0m0,410 s用户0m0,399 s sys 0m0,011 s
  • perl -ne ' { s/"//g; print if $. > 1 }' file.txt $ time -ne‘{ s/"//g;打印if $. >1 }’file.txt 1> /dev/空实0m0,379 s用户0m0,367 s sys 0m0,013 s

我重复了很多次测试,而且我总是得到类似的数字。如您所见,tail -n +2 file.txt | tr -d \"比其他<#>much速度更快。为什么?

EN

回答 4

Unix & Linux用户

回答已采纳

发布于 2020-05-21 14:07:52

这可以归结为所做的工作量。

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

  • 在……里面tail
    • 读到换行符;
    • 输出所有剩馀的东西,而不关心新行;

  • tr中,阅读,不关心换行符,输出除“”(一个固定字符)以外的所有内容。

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

  • 读到换行符,积累输入;
  • 如果这是第一行,就删除它;
  • 在解释正则表达式之后,将所有双引号替换为空;
  • 输出加工线;
  • 循环到文件的末尾。

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

  • 读到换行符,积累输入;
  • 在解释正则表达式之后,将所有双引号替换为空;
  • 如果这不是第一行,则输出处理过的行;
  • 循环到文件的末尾。

寻找新行的结果是在大型输入上花费很大。

票数 12
EN

Unix & Linux用户

发布于 2020-05-21 14:03:27

主要是因为perl和sed分别处理每一行。

如果让perl按更大的块处理输入,并将其简化一点(请参阅注),您可以使它变得更快--但没有比tr更快的了:

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

注意:不要使用perl -ne '... if $. > 1'awk 'NR == 1 { ... } /foo/ { ... }'

使用BEGIN{<>}BEGIN{getline}代替。

在您阅读了第一行之后,您可以非常确信以后的行不再是第一行了:不需要一遍又一遍地检查。

票数 7
EN

Unix & Linux用户

发布于 2020-05-21 21:17:21

tail_lines()来自尾.c:

代码语言:javascript
复制
      /* Use file_lines only if FD refers to a regular file for
         which lseek (... SEEK_END) works.  */

      if ( ! presume_input_pipe
           && S_ISREG (stats.st_mode)
           && (start_pos = lseek (fd, 0, SEEK_CUR)) != -1
           && start_pos < (end_pos = lseek (fd, 0, SEEK_END)))

这个end_pos = lseek (fd, 0, SEEK_END)是跳过文件内容的地方。在file_lines()中有反向扫描,计数换行符。

write()是一个非常简单的系统调用,用于重新定位文件偏移量以进行读/写。

哦,看来我错过了这个问题中的微妙之处),这一切都是关于阅读直线与方块。通常情况下,将多个传球组合成一个复杂的传球是个好主意。但是在这里,算法只需要第一行换行符。

Ole用sysread()编写的两部分perl脚本说明了他如何从搜索第一行换行符(S)切换到读取最大块。

tail正常工作时,它读取最后一个块并计数换行符。它是从那里打印出来的,或者是读到下一个街区。

票数 2
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/588127

复制
相关文章

相似问题

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