除了编码风格问题以外,并假设异常永远不会触发,相比于没有异常处理程序和使用0比较的if语句,在性能方面使用异常处理程序有多少差异?
为什么不使用timeit
模块来测量呢?这样你就可以看到它是否与你的应用程序相关。
好的,所以我刚刚尝试了以下操作(在Windows 11上使用Python 3.11.1):
import timeit
statements=["""\
try:
b = 10/a
except ZeroDivisionError:
pass""",
"""\
if a:
b = 10/a""",
"b = 10/a"]
for a in (1,0):
for s in statements:
t = timeit.Timer(stmt=s, setup='a={}'.format(a))
print("a = {}\n{}".format(a,s))
print("%.2f usec/pass\n" % (1000000 * t.timeit(number=100000)/100000))
结果:
a = 1
try:
b = 10/a
except ZeroDivisionError:
pass
0.06 usec/pass
a = 1
if a:
b = 10/a
0.05 usec/pass
a = 1
b = 10/a
0.03 usec/pass
a = 0
try:
b = 10/a
except ZeroDivisionError:
pass
0.27 usec/pass
a = 0
if a:
b = 10/a
0.02 usec/pass
a = 0
b = 10/a
Traceback (most recent call last):
File "<stdin>", line 5, in <module>
File "C:\Python311\Lib\timeit.py", line 178, in timeit
timing = self.inner(it, self.timer)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<timeit-src>", line 6, in inner
ZeroDivisionError: division by zero
正如您所见,使用 try/except
语句与显式的 if
语句之间没有太大区别,除非触发异常。 (当然,没有任何控制结构是最快的,尽管不会快多少,并且如果出现问题,它将使程序崩溃)。
将其与2010年获得的结果进行比较:
a = 1
try:
b = 10/a
except ZeroDivisionError:
pass
0.25 usec/pass
a = 1
if a:
b = 10/a
0.29 usec/pass
a = 1
b = 10/a
0.22 usec/pass
a = 0
try:
b = 10/a
except ZeroDivisionError:
pass
0.57 usec/pass
a = 0
if a:
b = 10/a
0.04 usec/pass
a = 0
b = 10/a
ZeroDivisionError: int division or modulo by zero
看起来我现在使用的电脑大约比我以前使用的快了两倍。处理异常的成本似乎相同,而“正常”的操作(算术)的改进甚至比控制结构的处理更多,但是那些年代的观点仍然存在:
所有这些都在同一数量级内,并且不太可能有所区别。只有在条件实际满足时(通常情况下),if
版本才会显着更快。
try/except
比if a != 0
更快。 - Thilo实际上,这个问题已经在设计和历史常见问题中得到了回答:
如果没有引发异常,try/except块非常高效。实际上,捕获异常是代价高昂的。
https://docs.python.org/3.11/whatsnew/3.11.html#optimizations
这个问题是误导性的。如果你假设异常永远不会被触发,那么两种代码都不是最优的。
如果你假设异常作为错误条件的一部分被触发,那么你已经超出了想要最优代码的范畴(而且你可能也不会以那种细粒度的方式处理它)。
如果你将异常作为标准控制流的一部分使用——这是Pythonic的“请求原谅,而不是事先获得许可”的方式——那么异常将被触发,成本取决于异常的类型、if的类型以及你估计异常发生的时间百分比。
try/catch
会有显著的性能损耗么?我在使用 try/catch
时需要担忧吗?有哪些方面需要注意吗?
这只是之前已经给出的答案的摘要。
if
语句比较快,否则没有区别。@SuperNova 表示,异常处理的成本为零,因此在没有异常的情况下,与 if-语句相比更快。但是,处理异常的成本很高,因此:
try:
x = getdata() # an external function
except:
print('failed. Retrying')
y = f(x) # f never fails but often returns 0
try:
z = 1 / y # this fails often
except:
print('failed.')
# if-version
y = f(x)
if y != 0:
z = 1 / y
else:
print('failed.')