Custo de manipuladores de exceção em Python

97

Em outra pergunta , a resposta aceita sugeria substituir uma instrução if (muito barata) no código Python por um bloco try / except para melhorar o desempenho.

Deixando de lado as questões de estilo de codificação, e supondo que a exceção nunca seja disparada, quanta diferença faz (em termos de desempenho) ter um manipulador de exceções em comparação a não ter um, em comparação a ter uma instrução if comparável a zero?

Thilo
fonte
6
Quando você mediu, o que você aprendeu?
S.Lott
1
Pergunta relacionada: stackoverflow.com/questions/1835756
tzot
Use try / except se as chances de controle indo para exceto parte forem menores e if / else se as chances forem maiores.
shadow0359

Respostas:

112

Por que você não mede usando o timeitmódulo ? Dessa forma, você pode ver se é relevante para seu aplicativo.

OK, acabei de tentar o seguinte:

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

Portanto, como esperado, não ter nenhum manipulador de exceção é um pouco mais rápido (mas explode na sua cara quando a exceção acontece) e try/excepté mais rápido do que um explícito if, desde que a condição não seja atendida.

Mas está tudo dentro da mesma ordem de magnitude e improvável que importe de qualquer maneira. Somente se a condição for realmente atendida, a ifversão será significativamente mais rápida.

Tim Pietzcker
fonte
3
Interessante. Então, try/excepté mais rápido do queif a != 0
Thilo
10
Ahh, uma bela escolha de palavras: "está tudo na mesma ordem de magnitude" ... Suspeito que muitas pessoas que evitam exceções o fazem esperando que sejam 10 vezes mais lentas.
Garrett Bluma
Executar seu código no meu Fedora com python 2.7.5 mostra que a versão "if" (0,08 usec / passagem) é mais rápida do que "tentar / exceto" (0,11 usec / passagem) quando a = 1.
duleshi
@duleshi Interessante. Eu me pergunto se é uma coisa x86 / x64? Ou talvez extensões de processador diferentes?
Básico de
58

Esta pergunta é realmente respondida nas Perguntas frequentes sobre design e história :

Um bloco try / except é extremamente eficiente se nenhuma exceção for levantada. Na verdade, capturar uma exceção é caro.

Michael
fonte
3
Eu estava me perguntando o quão eficiente é "extremamente eficiente". Aparentemente, é mais rápido do que até mesmo uma instrução "if" muito simples.
Thilo
O trecho que você postou é das Perguntas frequentes sobre design e história .
nitsas
Talvez "extremamente eficiente" signifique algo como o que é feito em Java ?
ebk
18

Esta pergunta é enganosa. Se você assumir que a exceção nunca é disparada, nenhum deles é o código ideal.

Se você presumir que a exceção é disparada como parte de uma condição de erro, você já está fora do reino de querer o código ideal (e provavelmente não está lidando com isso em um nível refinado como aquele).

Se você estiver usando a exceção como parte do fluxo de controle padrão - que é a forma pitônica "peça perdão, não permissão" - então a exceção será acionada e o custo depende do tipo de exceção, o tipo de se e em que porcentagem de tempo você estima que a exceção aconteça.


fonte