Python中异常处理程序的开销

yks3o0rb  于 2023-02-02  发布在  Python
关注(0)|答案(5)|浏览(133)

another question中,公认的答案是用try/except块替换Python代码中的if语句(非常便宜),以提高性能。
撇开编码风格问题不谈,假设异常从未被触发过,那么有一个异常处理程序,与没有异常处理程序,与有一个与零比较的if语句相比,在性能方面有多大的区别?

jv4diomz

jv4diomz1#

为什么不使用timeit module来测量它呢?这样就可以看到它是否与您的应用相关。
好的,我刚刚尝试了以下方法(在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

我现在使用的PC机比我以前使用的PC机快了两倍,处理异常的成本似乎是一样的,"正常"操作(算术)的改进甚至超过了控制结构的处理,但多年前的观点仍然存在:
所有这些都在同一个数量级内,而且不太可能有任何影响,只有当条件实际上得到满足(经常)时,if版本才明显更快。

wkftcu5l

wkftcu5l2#

此问题实际上在设计和历史常见问题解答中得到了解答:
如果不引发异常,try/except代码块是非常有效的。实际上,捕获异常的开销很大。

pw9qyyiw

pw9qyyiw3#

这个问题是误导性的,如果你假设异常是“从不”触发的,那么这两种代码都不是最优的。
如果您假设异常是作为错误条件的一部分触发的,那么您已经超出了需要最佳代码的范围(而且您可能不会像那样在细粒度级别上处理它)。
如果你把异常作为标准控制流的一部分--这是Python的“请求原谅,而不是请求许可”的方式--那么异常就会被触发,而成本取决于异常的类型、如果的类型以及你估计异常发生的时间百分比。

mu0hgdu0

mu0hgdu04#

在Python 3.11中,
“Zero-cost” exceptions are implemented. The cost of try statements is almost eliminated when no exception is raised. (Contributed by Mark Shannon in bpo-40222.)
https://docs.python.org/3.11/whatsnew/3.11.html#optimizations

fnx2tebb

fnx2tebb5#

问:try/catch在python中的开销大吗?

当我使用try catch时,我应该关注吗?以什么方式?
这只是对已经给出的答案的总结。

答:当出现异常时,if会快得多。否则就不会。

@SuperNova写道,异常的成本为零,因此在没有异常的情况下,它比使用if语句**要快。但是,处理异常的成本很高,因此:

对可能失败的操作使用try。如果可能,避免对知道会失败的操作使用try
示例:

1.好案例,使用尝试:

try:
    x = getdata() # an external function 
except:
    print('failed. Retrying')

1.不好的情况,此处首选if-version:

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.')

相关问题