评论会减慢直译语言的速度吗?

我问这个问题是因为我使用 Python,但它也可以应用于其他解释语言(Ruby、 PHP、 JavaScript)。

当我在代码中留下注释时,我是否减慢了解释器的速度?根据我对解释器的有限理解,它将程序表达式作为字符串读入,然后将这些字符串转换为代码。似乎每次解析注释都是在浪费时间。

是这样吗? 在解释语言中注释是否有一些约定,或者其影响可以忽略不计?

16421 次浏览

注释通常在解析阶段或之前被剥离,而且解析非常快,因此有效的注释不会减慢初始化时间。

这种效果在日常使用中可以忽略不计。它很容易测试,但是如果你考虑一个简单的循环,比如:

For N = 1 To 100000: Next

你的电脑可以处理这个(数到100,000)比你眨眼还快。忽略以某个特定字符开头的文本行的速度会快10,000倍以上。

别担心。

有注释将减慢启动时间,因为脚本将被解析为可执行表单。然而,在大多数情况下,注释并不会降低运行时的速度。

此外,在 python 中,可以编译。将 py 文件转换成。Pyc,它不会包含注释(我希望如此)-这意味着如果脚本已经编译过了,那么也不会有启动命中。

对于 Python,源文件在执行之前被编译(.pyc文件) ,注释在过程中被删除。因此,如果有大量的 可以注释,它们会减慢编译时间,但不会影响执行时间。

好吧,我写了一个像这样的简短的 Python 程序:

for i in range (1,1000000):
a = i*10

这个想法是,做一个简单的计算负载的时间。

通过计时,它运行了0.35 ± 0.01秒。

然后我重写了整本詹姆斯国王的圣经,像这样插入:

for i in range (1,1000000):
"""
The Old Testament of the King James Version of the Bible


The First Book of Moses:  Called Genesis




1:1 In the beginning God created the heaven and the earth.


1:2 And the earth was without form, and void; and darkness was upon
the face of the deep. And the Spirit of God moved upon the face of the
waters.


1:3 And God said, Let there be light: and there was light.


...
...
...
...


Even so, come, Lord Jesus.


22:21 The grace of our Lord Jesus Christ be with you all. Amen.
"""
a = i*10

这次的运行时间为0.4 ± 0.05秒。

所以答案是 是的.4 MB 的注释在一个循环中会产生可测量的差异。

这取决于如何实现解释器。大多数相当现代的解释器在任何实际执行之前都会对源代码进行一些预处理,包括删除注释,这样从那时起它们就不会有什么不同了。

曾几何时,当内存受到严重限制时(例如,64K 的总可寻址内存,以及用于存储的磁带) ,你不能想当然地认为这样的事情是理所当然的。回到 Apple II、 Commodore PET、 TRS-80等等的时代,程序员显式删除注释(甚至空白)以提高执行速度是相当常规的。这也只是在 1时期经常使用的众多源代码级别的黑客之一。

当然,这也有助于这些机器拥有一次只能执行一条指令的 CPU,时钟速度在1MHz 左右,并且只有8位处理器寄存器。即使是你现在只能在垃圾箱里找到的机器也比那些机器快得多,这一点都不好笑..。


1.另一个例子是,在苹果软件中,你可以根据你如何给行编号来增加或减少一点速度。如果我没记错的话,当 goto 语句的目标是16的倍数时,速度增加。

我对 解释器是它读程序 表达式作为字符串并进行转换 把这些字符串转换成代码。


大多数译员读取文件中的文本(代码)并产生一个抽象语法树的数据结构,因为它可以很容易地在下一阶段的编译中读取。 该结构不包含任何代码,以文本形式,当然也没有注释。只要那棵树就足以执行程序了。但是,出于效率的原因,解释器更进一步,产生字节码。巨蟒就是@么做的。

我们可以说代码和注释,以你写的形式,只是 不在场,
当程序运行时,注释不会减慢程序的运行速度。



注意: 解释器不使用文本以外的其他内部结构来表示代码,
即一个语法树,必须完全做你提到的。解释一遍又一遍的代码在运行时。

用一些注释(只有大约500kb 的文本)编写了一个类似 Rich 的脚本:

# -*- coding: iso-8859-15 -*-
import timeit


no_comments = """
a = 30
b = 40
for i in range(10):
c = a**i * b**i
"""
yes_comment = """
a = 30
b = 40


# full HTML from http://en.wikipedia.org/
# wiki/Line_of_succession_to_the_British_throne


for i in range(10):
c = a**i * b**i
"""
loopcomment = """
a = 30
b = 40


for i in range(10):
# full HTML from http://en.wikipedia.org/
# wiki/Line_of_succession_to_the_British_throne


c = a**i * b**i
"""


t_n = timeit.Timer(stmt=no_comments)
t_y = timeit.Timer(stmt=yes_comment)
t_l = timeit.Timer(stmt=loopcomment)


print "Uncommented block takes %.2f usec/pass" % (
1e6 * t_n.timeit(number=100000)/1e5)
print "Commented block takes %.2f usec/pass" % (
1e6 * t_y.timeit(number=100000)/1e5)
print "Commented block (in loop) takes %.2f usec/pass" % (
1e6 * t_l.timeit(number=100000)/1e5)


C:\Scripts>timecomment.py
Uncommented block takes 15.44 usec/pass
Commented block takes 15.38 usec/pass
Commented block (in loop) takes 15.57 usec/pass


C:\Scripts>timecomment.py
Uncommented block takes 15.10 usec/pass
Commented block takes 14.99 usec/pass
Commented block (in loop) takes 14.95 usec/pass


C:\Scripts>timecomment.py
Uncommented block takes 15.52 usec/pass
Commented block takes 15.42 usec/pass
Commented block (in loop) takes 15.45 usec/pass

根据大卫的评论进行编辑:

 -*- coding: iso-8859-15 -*-
import timeit


init = "a = 30\nb = 40\n"
for_ = "for i in range(10):"
loop = "%sc = a**%s * b**%s"
historylesson = """
# <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
# blah blah...
# --></body></html>
"""
tabhistorylesson = """
# <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
# blah blah...
# --></body></html>
"""


s_looped = init + "\n" + for_ + "\n" + tabhistorylesson + loop % ('   ','i','i')
s_unroll = init + "\n"
for i in range(10):
s_unroll += historylesson + "\n" + loop % ('',i,i) + "\n"
t_looped = timeit.Timer(stmt=s_looped)
t_unroll = timeit.Timer(stmt=s_unroll)


print "Looped length: %i, unrolled: %i." % (len(s_looped), len(s_unroll))


print "For block takes %.2f usec/pass" % (
1e6 * t_looped.timeit(number=100000)/1e5)
print "Unrolled it takes %.2f usec/pass" % (
1e6 * t_unroll.timeit(number=100000)/1e5)


C:\Scripts>timecomment_unroll.py
Looped length: 623604, unrolled: 5881926.
For block takes 15.12 usec/pass
Unrolled it takes 14.21 usec/pass


C:\Scripts>timecomment_unroll.py
Looped length: 623604, unrolled: 5881926.
For block takes 15.43 usec/pass
Unrolled it takes 14.63 usec/pass


C:\Scripts>timecomment_unroll.py
Looped length: 623604, unrolled: 5881926.
For block takes 15.10 usec/pass
Unrolled it takes 14.22 usec/pass

正如其他答案已经指出的那样,Python 这样的现代直译语言首先解析并将源代码编译成字节码,而解析器只是忽略注释。这清楚地表明,只有在源代码实际被解析时,才会出现速度损失。

因为解析器忽略注释,所以编译阶段基本上不受您输入的任何注释的影响。但是注释本身中的字节实际上被读入,然后在解析过程中跳过。这意味着,如果你有大量的注释(例如几百兆字节) ,这会降低解释器的速度。但是这也会降低编译器的速度。

我想知道如何使用注释是否重要。例如,三重引号是一个 docstring。如果使用它们,则验证内容。不久前,我在 Python 3代码中导入一个库时遇到了一个问题... ... 我在 N 上得到了一个关于语法的错误。我查看了行号,它是一个三引号注释中的内容。我有点惊讶。对 Python 来说,我从来没有想过一个块注释会被解释为语法错误。

只要你输入:

'''
(i.e. \Device\NPF_..)
'''

Python 2不会抛出错误,但 Python 3报告: 语法错误: (unicode 错误)‘ unicodeescape’编解码器无法解码位置为14-15的字节: N 个字符转义错误

所以 Python3显然是在解释三重引号,确保它是有效的语法。

但是,如果转换成单行注释: # (即设备 NPF _. .)
没有错误结果。

我想知道是否将三引号注释替换为单行,是否会看到性能变化。

这个问题确实很老了,但是在阅读了公认的答案,声称它不会影响执行时间,这是错误的,我给你一个简单的例子,你可以看到和检查的数量,它影响执行时间的确。
我有一个名为 constants.py的文件,它包含了国际象棋中所有不同的动作:

LABELS = [ "a1b1"
"a1c1",
"a1d1",
"a1e1",
"a1f1",....]

列表 LABELS包含2272个元素,在另一个文件中我调用:

import constants
np.array(constants.LABELS)

我测量了10次,代码的执行大约需要0.597毫秒。 现在我更改了文件,并在每个元素旁边(2272次)插入了一条注释:

LABELS = [ "a1b1",  # 0
"a1c1", # 1
"a1d1", # 2
"a1e1", # 3
"a1f1", # 4
...,
"Q@h8", # 2271]

现在,在测量了十次 np.array(constants.LABELS)的执行时间之后,我得到了4.28 ms 的平均执行时间,因此,大约慢了7倍。
因此,是的,如果有很多注释,它会影响执行时间。