Costo de los controladores de excepciones en Python

97

En otra pregunta , la respuesta aceptada sugirió reemplazar una declaración if (muy barata) en el código Python con un bloque try / except para mejorar el rendimiento.

Dejando de lado los problemas de estilo de codificación, y asumiendo que la excepción nunca se activa, ¿cuánta diferencia hace (en términos de rendimiento) tener un controlador de excepciones, en comparación con no tener uno, en comparación con una declaración if de comparación a cero?

Thilo
fuente
6
Cuando lo midió, ¿qué aprendió?
S.Lott
1
Pregunta relacionada: stackoverflow.com/questions/1835756
tzot
Utilice try / excepto si las posibilidades de que el control vaya a la excepción son menores y if / else si las posibilidades son mayores.
shadow0359

Respuestas:

112

¿Por qué no lo mides usando el timeitmódulo ? De esa manera, puede ver si es relevante para su aplicación.

Bien, acabo de intentar lo siguiente:

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

Resultado:

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

Entonces, como se esperaba, no tener ningún controlador de excepciones es un poco más rápido (pero explota en su cara cuando ocurre la excepción) y try/exceptes más rápido que un explícito ifsiempre que no se cumpla la condición.

Pero todo está dentro del mismo orden de magnitud y es poco probable que importe de cualquier manera. Solo si realmente se cumple la condición, la ifversión es significativamente más rápida.

Tim Pietzcker
fuente
3
Interesante. Entonces try/exceptes más rápido queif a != 0
Thilo
10
Ahh, una buena elección de palabras: "todo está dentro del mismo orden de magnitud" ... Sospecho que muchas personas que evitan las excepciones lo hacen esperando que sean 10 veces más lentas.
Garrett Bluma
Ejecutar su código en mi Fedora con python 2.7.5 muestra que la versión "si" (0.08 usec / pass) es más rápida que la versión "try / except" (0.11 usec / pass) cuando a = 1.
duleshi
@duleshi Interesante. Me pregunto si es una cosa x86 / x64. ¿O quizás diferentes extensiones de procesador?
Básico
58

Esta pregunta se responde realmente en las Preguntas frecuentes sobre diseño e historia :

Un bloque try / except es extremadamente eficiente si no se generan excepciones. De hecho, detectar una excepción es caro.

Miguel
fuente
3
Me preguntaba qué tan eficiente es "extremadamente eficiente". Aparentemente, es más rápido que incluso una simple declaración "si".
Thilo
El extracto que publicó es de las Preguntas frecuentes sobre diseño e historia .
nitsas
¿Quizás "extremadamente eficiente" significa algo como lo que se hace en Java ?
ebk
18

Esta pregunta es engañosa. Si asume que la excepción nunca se activa, ninguno de los dos es el código óptimo.

Si asume que la excepción se activa como parte de una condición de error, ya está fuera del ámbito de querer un código óptimo (y probablemente no lo esté manejando a un nivel detallado como ese de todos modos).

Si está utilizando la excepción como parte del flujo de control estándar, que es la forma Pythonic de "pedir perdón, no permiso", entonces la excepción se activará y el costo dependerá del tipo de excepción, el tipo de si y el porcentaje de tiempo que estima que ocurre la excepción.


fuente