Python 中异常处理程序的成本

问题描述 投票:0回答:5

另一个问题中,接受的答案建议用 try/ except 块替换 Python 代码中的(非常便宜的)if 语句以提高性能。

抛开编码风格问题不谈,假设永远不会触发异常,那么拥有一个异常处理程序、没有异常处理程序、以及拥有一个与零进行比较的 if 语句,(在性能方面)有多大区别?

python performance exception micro-optimization
5个回答
156
投票

为什么不使用

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
版本才会明显更快。


82
投票

这个问题实际上在设计和历史常见问题解答中得到了回答:

如果没有引发异常,则 try/ except 块非常高效。 实际上捕获异常是昂贵的。


31
投票

在 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#misc


22
投票

这个问题具有误导性。如果您假设“从不”触发异常,则两者都不是最佳代码。 如果您假设异常是作为错误条件的一部分触发的,那么您已经超出了想要最佳代码的范围(而且您可能不会以这样的细粒度级别处理它)。

如果您使用异常作为标准控制流的一部分 - 这是Python式的“请求宽恕,而不是许可”方式 - 那么异常将被触发,并且成本取决于异常的类型,异常的类型如果,以及您估计异常发生的时间百分比。


8
投票
try/catch
在Python中代价昂贵吗?
当我使用 try catch 时我应该担心吗?通过什么方式?

这只是已经给出的答案的摘要。

A:当出现异常时

if
要快得多。否则不行。
@SuperNova 写道,异常的成本为零,因此它比没有异常时使用 if 语句更快。然而,处理异常的成本很高:

对可能失败的事情使用 try。如果可能的话,避免尝试你知道会失败的事情 示例:

好案例,使用试试:
    try: x = getdata() # an external function except: print('failed. Retrying')
不好的情况,这里首选 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.')
© www.soinside.com 2019 - 2024. All rights reserved.