Koszt obsługi wyjątków w Pythonie

97

W innym pytaniu przyjęta odpowiedź sugerowała zastąpienie (bardzo tanie) wyrażenia if w kodzie Pythona blokiem try / except, aby poprawić wydajność.

Pomijając kwestie związane ze stylem kodowania, a zakładając, że wyjątek nigdy nie jest wyzwalany, jaką różnicę (pod względem wydajności) robi posiadanie programu obsługi wyjątków w porównaniu z brakiem go w porównaniu z instrukcją if-porównania z zerową wartością?

Thilo
źródło
6
Czego się nauczyłeś, mierząc to?
S.Lott,
1
Powiązane pytanie: stackoverflow.com/questions/1835756
tzot
Użyj try / except, jeśli szanse na kontrolę, z wyjątkiem części są mniejsze i if / else, jeśli szanse są większe.
shadow0359

Odpowiedzi:

112

Dlaczego nie zmierzysz tego za pomocą timeitmodułu ? W ten sposób możesz sprawdzić, czy jest to istotne dla Twojej aplikacji.

OK, więc właśnie spróbowałem następujących rzeczy:

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

Wynik:

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

Tak więc, zgodnie z oczekiwaniami, brak obsługi wyjątków jest nieco szybszy (ale wybucha ci w twarz, gdy zdarza się wyjątek) i try/exceptjest szybszy niż jawny, ifo ile warunek nie jest spełniony.

Ale wszystko jest w tym samym rzędzie wielkości i jest mało prawdopodobne, aby miało to znaczenie. Tylko jeśli warunek jest rzeczywiście spełniony, ifwersja jest znacznie szybsza.

Tim Pietzcker
źródło
3
Ciekawy. Więc try/exceptjest szybszy niżif a != 0
Thilo
10
Ach, dobry dobór słów: „wszystko mieści się w tym samym rzędzie wielkości”… Podejrzewam, że wiele osób, które unikają wyjątków, robi to, spodziewając się, że będą działać 10 razy wolniej.
Garrett Bluma
Uruchomienie kodu na mojej Fedorze z Pythonem 2.7.5 pokazuje, że wersja „jeśli” (0,08 usek / przebieg) jest szybsza niż wersja „try / z wyjątkiem” (0,11 usek / przebieg), gdy a = 1.
duleshi
@duleshi Interesting. Zastanawiam się, czy to sprawa x86 / x64? A może inne rozszerzenia procesora?
Podstawowy
58

Odpowiedź na to pytanie znajduje się w często zadawanych pytaniach dotyczących projektowania i historii :

Blok try / except jest niezwykle skuteczny, jeśli nie są zgłaszane żadne wyjątki. Właściwie złapanie wyjątku jest kosztowne.

Michael
źródło
3
Zastanawiałem się tylko, jak skuteczne jest „niezwykle wydajne”. Najwyraźniej jest to szybsze niż nawet bardzo proste stwierdzenie „jeśli”.
Thilo
Opublikowane przez Ciebie fragmenty pochodzą z często zadawanych pytań dotyczących projektowania i historii .
nitsas
Może „niezwykle wydajne” oznacza coś takiego, jak robi się to w Javie ?
ebk
18

To pytanie jest mylące. Jeśli założysz, że wyjątek nigdy nie jest wyzwalany, żaden z nich nie jest optymalnym kodem.

Jeśli założysz, że wyjątek jest wyzwalany jako część warunku błędu, jesteś już poza obszarem poszukiwania optymalnego kodu (i prawdopodobnie i tak nie obsługujesz go na tak drobnoziarnistym poziomie).

Jeśli używasz wyjątku jako części standardowego przepływu sterowania - który jest sposobem Pythona „poproś o wybaczenie, nie o pozwolenie” - wtedy wyjątek zostanie wyzwolony, a koszt zależy od jego rodzaju, rodzaju i szacowany procent czasu wystąpienia wyjątku.


źródło