当我陈述以下内容时,我的理解是否正确:
在 while(<>) 循环中测试 $ARGV(即文件名)的某些条件会浪费 CPU 周期。首先测试文件名更有效,然后在 while() 循环中相应地处理每一行。这样,它就不会在每次抓取一行数据时重复检查文件名。
或者钻石操作员是否做了一些魔术来使其与后者一样高效?
当我陈述以下内容时,我的理解是否正确:
在 while(<>) 循环中测试 $ARGV(即文件名)的某些条件会浪费 CPU 周期。首先测试文件名更有效,然后在 while() 循环中相应地处理每一行。这样,它就不会在每次抓取一行数据时重复检查文件名。
或者钻石操作员是否做了一些魔术来使其与后者一样高效?
它是在浪费 CPU 周期吗?
您正在运行Perl。在VM上运行。你知道一个简单的全局变量查找意味着多少指针取消引用吗?你为什么要关心周期?/s
尽管<>
运算符确实暗示了相当多的魔法,但这并没有优化您的循环。因此,在
my $lastfile = "";
while (<>) {
say "file changed to ", $lastfile = $ARGV if $lastfile ne $ARGV;
print "> $_";
}
将对ne
每一行执行检查。如果您正在优化代码大小或开发时间,这是完全可以接受的。如果您正在优化执行的操作码总数,有时显式打开文件可能会更便宜:
use autodie;
for my $file (@ARGV) {
open my $fh, "<", $file;
say "file changed to $file";
while (<$fh>) {
print "> $_";
}
}
我个人觉得这种形式更优雅(单一分配形式),反正也不会那么长。但是在一个快速的单行器中,我会使用第一个解决方案,因为我的脚本可能已经运行了一千次,而我仍在编写更长的表单。
作为概念证明(见下文),我在一个 10 亿行的文件上运行了 amon 所示的两个脚本(我分别将它们命名为 poc.pl 和 poc2.pl)。前者慢了 21.7%。总之,这仅在处理大量行时才有意义。在这种情况下,低级语言可能是更好的选择。
bash $ wc -l large.log
1000000000 large.log
bash $ time perl poc.pl large.log >/dev/null
291.16s real 289.89s user 0.73s system
bash $ time perl poc2.pl large.log >/dev/null
239.29s real 238.58s user 0.53s system