我之所以问这个问题是因为我使用 Python,但其他解释型语言(如 Ruby、PHP 和 JavaScript)可能也适用。
当我在代码中留下注释时,是否会减慢解释器的速度?根据我对解释器的有限理解,它将程序表达式作为字符串读入,然后将这些字符串转换为代码。每次解析注释时,似乎都浪费了时间。
这是真的吗?在解释型语言中是否有关于注释的约定,还是其影响可以忽略不计?
我之所以问这个问题是因为我使用 Python,但其他解释型语言(如 Ruby、PHP 和 JavaScript)可能也适用。
当我在代码中留下注释时,是否会减慢解释器的速度?根据我对解释器的有限理解,它将程序表达式作为字符串读入,然后将这些字符串转换为代码。每次解析注释时,似乎都浪费了时间。
这是真的吗?在解释型语言中是否有关于注释的约定,还是其影响可以忽略不计?
对于 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秒。
所以答案是是。在循环中有4MB的注释确实会产生可测量的差异。
在解析阶段之前或之后通常会删除注释,而解析非常快,因此实际上注释不会减慢初始化时间。
这个效果在日常使用中可以忽略不计。测试很容易,但是如果你考虑一个简单的循环,比如:
For N = 1 To 100000: Next
你的电脑可以比你眨眼更快地处理那个(数到100,000)。忽略以某个特定字符开头的文本行将比这快10,000多倍。
不用担心。
我用类似Rich的脚本写了一些注释(只有约500kb的文本):
# -*- 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
根据David评论的修改:
-*- 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 这样的现代解释型语言首先会将源代码解析和编译成字节码,而解析器会忽略注释。这意味着在启动时实际解析源代码时才会出现任何速度损失。
由于解析器忽略注释,因此编译阶段基本上不受您放置的任何注释的影响。但是注释中的字节实际上是被读取并在解析过程中被跳过的。这意味着,如果您有大量注释(例如许多百兆字节),这将减慢解释器的速度。但是同样也会影响任何编译器。
我想知道评论的用法是否很重要。例如,三引号表示文档字符串。如果使用它们,则可以验证内容。不久前,我在将库导入我的Python 3代码时遇到了一个问题......我收到有关\N语法错误的错误。我查看了行号,发现是在三引号注释中的内容引起的。我有些惊讶。作为Python的新手,我从未想过块注释会被解释为语法错误。
简而言之,如果您键入:
'''
(i.e. \Device\NPF_..)
'''
Python 2不会报错,但是Python 3会报错: SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 14-15: malformed \N character escape
所以显然Python 3会解释三引号,并确保它是有效的语法。
然而,如果将其转换为单行注释:#(即\Device\NPF_..)
不会出现错误。
我想知道如果将三引号注释替换为单行注释,是否会有性能上的变化。