如何防止Perl文本处理任务中自动处理换行杀死性能?

问题描述 投票:0回答:1

TL;博士:

perl5 中的自动行尾处理似乎会降低性能。是否有可能通过手动添加换行符而不是使用

say
-l
来缓解这种情况而不牺牲便利性?


长版:

我反复想知道,为什么我自己对 perl5(感觉很快)与 python 的字符串处理速度的比较(感觉很快)的体验与基准游戏网页上可能客观的性能比较(例如在 fasta 示例中 perl 是慢的)。我发现引人注目的是:所有世界似乎都使用“say”进行普通输出,而这里的奇怪家伙坚持使用“print”并手动添加“ ”.

所以我设置了一个最小的例子:

  1. 从 1 数到语言本身的任意数字。
  2. 对于每一步,在新行中输出数字。
  3. 整个过程重复三遍
  4. 在标准输出重定向到
    /dev/null
  5. 时,取这三个运行的最短时间

整个事情是通过三种不同的方法完成的:

  1. 使用 Perl 的普通“打印”语句并每次都显式附加换行符
  2. 或者使用“-l”调用perl,这可以启用自动换行符处理(再次使用打印)
  3. 第三种选择:使用“say”功能,它也会自动处理这个问题

对于每种方法,我都对比了输出缓冲状态(启用与禁用)。

当我看到禁用输出缓冲区对性能的影响远小于启用自动行尾处理时,我感到震惊 - 后者使运行时间增加了一倍多。

Records/sec  n_total Time Command
 7120052.46 10000000 1.40 perl -e '$|=0; for (my $i=1; $i<=10000000;$i++) {print $i . "\n";};'          
 4961279.63 10000000 2.02 perl -e '$|=1; for (my $i=1; $i<=10000000;$i++) {print $i . "\n";};'          
 2821234.16 10000000 3.54 perl -l -e '$|=0; for (my $i=1; $i<=10000000;$i++) {print $i;};'                
 2462226.44 10000000 4.06 perl -l -e '$|=1; for (my $i=1; $i<=10000000;$i++) {print $i;};' 
 2898328.96 10000000 3.45 perl -e 'use feature "say"; $|=0; for (my $i=1; $i<=10000000;$i++) {say $i;};'  
 2452486.23 10000000 4.08 perl -e 'use feature "say"; $|=1; for (my $i=1; $i<=10000000;$i++) {say $i;};'  

问题:

虽然目前看来手动添加行尾似乎值得,但这仍然有点麻烦:是否有任何我在这里错过的开关,并且可以防止使用“say”或“-”时输出性能的下降l”开关?


FWIW:

当我已经陷入兔子洞时,我无法自拔。所以我继续...

为了获得更全面的了解,我最终继续将上述内容与我日常使用的其他工具(主要是 gawk,因为最近也使用了一点 jq)进行了比较,或者过去使用过(python 甚至更早的 tcl)或者只是涉足有时候(口齿不清的味道)。全部在运行 cygwin 的 Windows 10 机器上。

现在的主要标准是选择数字,使其在我的机器上运行 10 秒内,并且仍然使运行数字具有一定的可比性(仅考虑 10 的幂)。 还对比了使用行缓冲区与在其他一些行之后刷新输出。

完整的故事是:在 Perl 中禁用输出缓冲区比在其他语言(特别是 Python)中更容易。对于某些人来说,我什至不想尝试(见下文)。

 Records/sec   n_total Time    Command
 46772945.30 100000000 2.14 -- seq 100000000
  7102358.15  10000000 1.41 -- perl -e '$|=0; for (my $i=1; $i<=10000000;$i++) {print $i . "\x0A";};'
  4851147.42  10000000 2.06 -- php -r 'for ($i=1; $i<=10000000;$i++) {echo $i . PHP_EOL;};'
  4524956.61  10000000 2.21 -- perl -e '$|=1; for (my $i=1; $i<=10000000;$i++) {print $i . "\x0A";};'
  2643538.99  10000000 3.78 -- perl -l -e '$|=0; for (my $i=1; $i<=10000000;$i++) {print $i;};'
  2542994.96  10000000 3.93 -- awk -e "BEGIN{for (i=1;i<=10000000;i++) print i}"
  2537951.85  10000000 3.94 -- perl -e '$|=0; use feature "say"; for (my $i=1; $i<=10000000;$i++) {say $i;};'
  2407226.07  10000000 4.15 -- luajit -e 'for i = 1,10000000 do print(i) end'
  2347240.89  10000000 4.26 -- perl -e '$|=1; use feature "say"; for (my $i=1; $i<=10000000;$i++) {say $i;};'
  2342141.92  10000000 4.27 -- perl -l -e '$|=1; for (my $i=1; $i<=10000000;$i++) {print $i;};'
  1869504.49  10000000 5.35 -- python -c 'for i in range(1,round(10000000)+1): print(i)'
  1641012.48  10000000 6.09 -- awk -e "BEGIN{for (i=1;i<=10000000;i++) {print i; fflush()}}"
  1591311.72  10000000 6.28 -- jq -n 'range(1;10000000+1)'
  1395488.79  10000000 7.17 -- lua -e 'for i = 1,10000000 do print(i) end'
   905889.95   1000000 1.10 -- echo 'for {set i 1} {$i <= 1000000} {incr i} {puts $i}' | tclsh
   516841.54   1000000 1.93 -- python -uc 'for i in range(1,round(1000000)+1): print(i)'
   263998.59   1000000 3.79 -- clisp -x '(loop for x from 1 to 1000000 do (print x))'
   139282.21   1000000 7.18 -- echo '(loop for x from 1 to 1000000 do (print x))' | sbcl

使用版本:Perl 5.36.3; Python 3.9.16; PHP 7.3.7; GAWK 5.3.0;卢阿 5.3.6;卢吉特 2.0.4; jq 1.7.1;剪辑 2.49.92; SBCL 2.4.9; tclsh 8.6.12;来自 GNU core utils 9.0 的 seq

string performance perl
1个回答
0
投票

TL;博士:

简单地引用数字变量似乎可以解决

say
-l

的问题

长版:

经过上述一些评论后,我进行了进一步的测试。 TLPjhnc 似乎有道理:

当使用

,
而不是
.
来组合变量值和 print 语句的换行符时,会减慢 print 调用,就像在原始帖子中使用“say”所做的那样。

但是,当引用变量时,速度并没有减慢。同样,通过引用变量,

say
-l
可以再次加速,其中
say
现在是最快的。请参阅下面的测试。

 Records/sec   n_total Time    Command
  6532779.83  10000000 1.53 -- perl -e '$|=0; for (my $i=1; $i<=10000000;$i++) {print $i . "\n";};'
  4812752.85  10000000 2.08 -- perl -e '$|=1; for (my $i=1; $i<=10000000;$i++) {print $i . "\n";};'
  2851817.48  10000000 3.51 -- perl -e '$|=0; for (my $i=1; $i<=10000000;$i++) {print $i, "\n";};'
  2292372.38  10000000 4.36 -- perl -e '$|=1; for (my $i=1; $i<=10000000;$i++) {print $i, "\n";};'
  7081385.63  10000000 1.41 -- perl -e '$|=0; for (my $i=1; $i<=10000000;$i++) {print "$i", "\n";};'
  5347508.00  10000000 1.87 -- perl -e '$|=1; for (my $i=1; $i<=10000000;$i++) {print "$i", "\n";};'
  2957947.16  10000000 3.38 -- perl -e '$|=0; use feature "say"; for (my $i=1; $i<=10000000;$i++) {say $i;};'
  2611186.85  10000000 3.83 -- perl -e '$|=1; use feature "say"; for (my $i=1; $i<=10000000;$i++) {say $i;};'
  7811974.89  10000000 1.28 -- perl -e '$|=0; use feature "say"; for (my $i=1; $i<=10000000;$i++) {say "$i";};'
  5600668.93  10000000 1.79 -- perl -e '$|=1; use feature "say"; for (my $i=1; $i<=10000000;$i++) {say "$i";};'
  2861258.14  10000000 3.49 -- perl -l -e '$|=0; for (my $i=1; $i<=10000000;$i++) {print $i;};'
  2341549.60  10000000 4.27 -- perl -l -e '$|=1; for (my $i=1; $i<=10000000;$i++) {print $i;};'
  7045289.66  10000000 1.42 -- perl -l -e '$|=0; for (my $i=1; $i<=10000000;$i++) {print "$i";};'
  4676765.18  10000000 2.14 -- perl -l -e '$|=1; for (my $i=1; $i<=10000000;$i++) {print "$i";};'
© www.soinside.com 2019 - 2024. All rights reserved.