8

我正在优化一些经常运行的 Perl 代码(每个文件每天一次)。

注释会减慢 Perl 脚本的速度吗?我的实验倾向于否:

use Benchmark;
timethese(20000000, {
    'comments' => '$b=1;
# comment  ... (100 times)
', 'nocomments' => '$b=1;'});

给出几乎相同的值(除了噪声)。

Benchmark: timing 10000000 iterations of comments, nocomments...
  comments:  1 wallclock secs ( 0.53 usr +  0.00 sys =  0.53 CPU) @ 18832391.71/s (n=10000000)
nocomments:  0 wallclock secs ( 0.44 usr +  0.00 sys =  0.44 CPU) @ 22935779.82/s (n=10000000)

Benchmark: timing 20000000 iterations of comments, nocomments...
  comments:  0 wallclock secs ( 0.86 usr + -0.01 sys =  0.84 CPU) @ 23696682.46/s (n=20000000)
nocomments:  1 wallclock secs ( 0.90 usr +  0.00 sys =  0.90 CPU) @ 22099447.51/s (n=20000000)

如果我将注释和无注释版本作为单独的 Perl 脚本运行,我会得到类似的结果。

不过,这似乎违反直觉,如果没有其他要求,解释器每次都需要将注释读入内存。

4

9 回答 9

18

运行时性能?不。

解析和词法分析性能?是的当然。

由于 Perl 倾向于动态解析和 lex,因此注释会影响“启动”性能。

它们会显着影响它吗?不太可能。

于 2008-11-06T20:03:33.367 回答
13

Perl 是一种即时编译语言,因此注释和 POD 对运行时性能没有影响。

注释和 POD 对编译时间的影响很小,但它们对 Perl 来说非常容易和快速解析,几乎不可能衡量性能影响。您可以通过使用该-c标志进行编译来亲自查看这一点。

在我的 Macbook 上,一个带有 2 个语句和 1000 行 70 个字符注释的 Perl 程序与一个只有 2 个打印语句的 1000 行空注释的编译时间相同。确保运行每个基准测试两次以允许您的操作系统缓存文件,否则您要进行基准测试的是从磁盘读取文件的时间。

如果启动时间对您来说是个问题,那不是因为评论和 POD。

于 2008-11-06T22:21:58.437 回答
8

Perl 编译一个脚本然后执行它。注释略微减慢了编译阶段,但对运行阶段的影响为零。

于 2008-11-06T20:03:25.020 回答
7

Perl 与 shell 脚本不同,它不是一种脚本语言。解释器不会逐行读取文件。Perl 程序的执行分为两个基本阶段:编译和运行时 [1]。在编译阶段,源代码被解析并转换为字节码。在运行时阶段,字节码在虚拟机上执行。

注释会减慢解析阶段,但与解析脚本本身所需的时间(对于大多数程序来说已经非常小)相比,差异可以忽略不计。您真正关心解析时间的唯一一次是在网络服务器环境中,该程序每秒可以调用多次。mod_perl 的存在就是为了解决这个问题。

你正在使用Benchmark. 那挺好的!你应该寻找改进算法的方法——而不是微优化。Devel::DProf 可能有助于找到任何热点。您绝对不应该在错误的尝试中删除注释以使您的程序更快。你只会让它无法维护。


[1] 这通常称为“及时”编译。Perl 实际上还有几个阶段,比如INITEND这里无关紧要。

于 2008-11-06T20:49:26.067 回答
3

重点是:优化瓶颈。读取文件包括:

  • 打开文件,
  • 阅读其内容,
  • 关闭文件,
  • 解析内容。

在这些步骤中,阅读是迄今为止最快的部分(我不确定是否要关闭,它是一个系统调用,但您不必等待它完成)。即使它是整个事情的 10%(我认为不是),然后将其减少一半只会提高 5% 的性能,代价是缺少评论(这是一件非常糟糕的事情)。对于解析器,丢弃以 # 开头的行并不是明显的减速。在那之后,评论就消失了,所以不能放慢速度。

现在,想象一下,通过删除所有评论,您实际上可以将“阅读脚本”部分提高 5%(这是一个非常乐观的估计,见上文)。“看剧本”占剧本总耗时的比例有多大?当然,这取决于它做了多少,但是由于 perl 脚本通常会读取至少一个文件,因此最多为 50%,但是由于 perl 脚本通常会做更多的事情,因此诚实的估计会将其降低到某个范围内1%。因此,剥离所有评论的 预期效率提升最多(非常乐观)2.5%,但实际上更接近 0.05%。然后,实际上提供超过 1% 的那些已经很快,因为它们几乎什么都不做,所以你再次在错误的点进行优化。

总结,优化瓶颈。

于 2008-11-06T20:54:12.797 回答
2

Benchmark 模块在这种情况下是无用的。它只是测量一遍又一遍地运行代码的时间。由于您的代码实际上并没有做任何事情,因此大部分代码都对其进行了优化。这就是为什么你会看到它每秒运行 2200 万次。

我在Mastering Perl中几乎整整一章都有这方面的内容。基准技术的测量误差约为 7%。您的基准数字在此范围内,因此几乎没有区别。

于 2008-11-06T23:19:44.827 回答
1

来自 Paul Tomblins 的评论:

perl 不做某种即时编译吗?也许评论会提前被丢弃?——</p>

是的,Perl 可以。

它是一种介于编译和解释之间的编程语言。代码被即时编译然后运行。评论通常没有任何区别。它可能会产生的最大影响是,当它最初逐行解析文件并预编译它时,您可能会看到纳秒级的差异。

于 2008-11-06T20:05:17.310 回答
0

我希望一条评论只会被解析一次,而不是在循环中多次解析,所以我怀疑这是一个有效的测试。

我希望注释会稍微减慢编译速度,但我认为删除它们太小了。

于 2008-11-06T20:04:13.927 回答
0

Perl 注释会减慢脚本的速度吗?好吧,解析它,是的。解析后执行?不。脚本多久被解析一次?只有一次,所以如果你在 for 循环中有注释,注释会被解析丢弃一次,在脚本甚至运行之前,一旦它开始运行,注释就已经消失了(并且脚本不会在内部存储为脚本Perl),因此无论 for 循环重复多少次,注释都不会产生影响。解析器跳过注释的速度有多快?Perl 注释的完成方式非常快,因此我怀疑你会注意到。如果您有 5 行代码,并且每行之间有 1 行 Mio 注释,您会注意到启动时间更长……但是这种可能性有多大,那么大的注释有什么用呢?

于 2008-11-06T20:40:49.047 回答