TL;博士:
perl5 中的自动行尾处理似乎会降低性能。是否有可能通过手动添加换行符而不是使用
say
或 -l
来缓解这种情况而不牺牲便利性?
长版:
我反复想知道,为什么我自己对 perl5(感觉很快)与 python 的字符串处理速度的比较(感觉很快)的体验与基准游戏网页上可能客观的性能比较(例如在 fasta 示例中 perl 是慢的)。我发现令人震惊的是:所有世界似乎都使用“say”进行普通输出,而这里的奇怪家伙坚持使用“print”并手动添加“ ”.
所以我设置了一个最小的例子:
/dev/null
整个事情是通过三种不同的方法完成的:
对于每种方法,我都对比了输出缓冲状态(启用与禁用)。
当我看到禁用输出缓冲区对性能的影响远小于启用自动行尾处理时,我感到震惊 - 后者使运行时间增加了一倍多。
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
TL;博士:
简单地引用数字变量似乎可以解决
say
和 -l
! 的问题
长版:
经过上述一些评论,我进行了进一步的测试。 TLP 和 jhnc 似乎有道理:
当使用
,
而不是 .
来组合变量值和 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";};'