Biaya penangan pengecualian dengan Python

97

Dalam pertanyaan lain , jawaban yang diterima menyarankan untuk mengganti pernyataan if (sangat murah) dalam kode Python dengan blok coba / kecuali untuk meningkatkan kinerja.

Mengesampingkan masalah gaya pengkodean, dan dengan asumsi bahwa pengecualian tidak pernah dipicu, seberapa besar perbedaan yang dibuat (dari segi kinerja) untuk memiliki penangan pengecualian, versus tidak memilikinya, versus memiliki pernyataan if-bandingkan-ke-nol?

Thilo
sumber
6
Ketika Anda mengukurnya, apa yang Anda pelajari?
S. Lotot
1
Pertanyaan terkait: stackoverflow.com/questions/1835756
tzot
Gunakan coba / kecuali jika peluang kontrol akan kecuali bagian lebih kecil dan jika / lain jika peluang lebih besar.
shadow0359

Jawaban:

112

Mengapa Anda tidak mengukurnya menggunakan timeitmodul ? Dengan begitu Anda dapat melihat apakah itu relevan dengan aplikasi Anda.

Oke, jadi saya baru saja mencoba yang berikut ini:

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

Hasil:

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

Jadi, seperti yang diharapkan, tidak memiliki penangan pengecualian sedikit lebih cepat (tetapi meledak di wajah Anda saat pengecualian terjadi), dan try/exceptlebih cepat daripada eksplisit ifselama kondisinya tidak terpenuhi.

Tapi itu semua dalam urutan yang sama besarnya dan tidak mungkin menjadi masalah. Hanya jika kondisi benar-benar terpenuhi, maka ifversinya jauh lebih cepat.

Tim Pietzcker
sumber
3
Menarik. Jadi try/exceptlebih cepat dariif a != 0
Thilo
10
Ahh, pilihan kata yang bagus: "semuanya dalam urutan yang sama besarnya" ... Saya curiga banyak orang yang menghindari pengecualian melakukannya dengan mengharapkan mereka menjadi 10x lebih lambat.
Garrett Bluma
Menjalankan kode Anda di Fedora saya dengan python 2.7.5 menunjukkan bahwa versi "if" (0.08 usec / pass) lebih cepat daripada versi "coba / kecuali" (0.11 usec / pass) saat a = 1.
duleshi
@Dulesh Menarik. Saya ingin tahu apakah itu x86 / x64? Atau mungkin ekstensi prosesor yang berbeda?
Dasar
58

Pertanyaan ini sebenarnya terjawab di FAQ Desain dan Sejarah :

Blok percobaan / pengecualian sangat efisien jika tidak ada pengecualian yang dimunculkan. Sebenarnya menangkap pengecualian itu mahal.

Michael
sumber
3
Saya hanya ingin tahu seberapa efisien "sangat efisien" itu. Rupanya itu lebih cepat daripada pernyataan "jika" yang sangat sederhana.
Thilo
Kutipan yang Anda posting berasal dari FAQ Desain dan Sejarah .
nitsas
Mungkin "sangat efisien" berarti seperti apa yang dilakukan di Java ?
surut
18

Pertanyaan ini menyesatkan. Jika Anda menganggap pengecualiannya adalah tidak pernah dipicu, tidak ada satu pun yang merupakan kode optimal.

Jika Anda menganggap pengecualian dipicu sebagai bagian dari kondisi kesalahan, Anda sudah berada di luar ranah menginginkan kode yang optimal (dan Anda mungkin tidak menanganinya pada tingkat yang sangat rinci seperti itu).

Jika Anda menggunakan pengecualian sebagai bagian dari aliran kontrol standar - yang merupakan cara Pythonic "minta maaf, bukan izin" - maka pengecualian akan dipicu, dan biayanya bergantung pada jenis pengecualian, jenis jika , dan berapa persentase waktu Anda memperkirakan pengecualian terjadi.


sumber