Selama tinjauan kode dengan karyawan Microsoft, kami menemukan sebagian besar kode di dalam try{}
blok. Dia dan perwakilan TI menyarankan ini dapat memiliki efek pada kinerja kode. Bahkan, mereka menyarankan sebagian besar kode harus di luar blok coba / tangkap, dan hanya bagian-bagian penting yang harus diperiksa. Karyawan Microsoft menambahkan dan mengatakan bahwa buku putih yang akan datang memperingatkan terhadap blok try / catch yang salah.
Saya telah melihat sekeliling dan menemukan itu dapat mempengaruhi pengoptimalan , tetapi tampaknya hanya berlaku ketika variabel dibagi di antara cakupan.
Saya tidak bertanya tentang kelestarian kode, atau bahkan menangani pengecualian yang benar (kode yang dipermasalahkan perlu dipertimbangkan ulang, tidak diragukan lagi). Saya juga tidak merujuk menggunakan pengecualian untuk kontrol aliran, ini jelas salah dalam kebanyakan kasus. Itu adalah masalah penting (beberapa lebih penting), tetapi bukan fokus di sini.
Bagaimana pengaruh coba / tangkap blok mempengaruhi kinerja ketika pengecualian tidak dilemparkan?
sumber
Jawaban:
Periksa.
Keluaran:
Dalam milidetik:
Kode baru:
Hasil baru:
sumber
Setelah melihat semua statistik dengan coba / tangkap dan tanpa coba / tangkap, rasa ingin tahu memaksa saya untuk melihat ke belakang untuk melihat apa yang dihasilkan untuk kedua kasus. Ini kodenya:
C #:
MSIL:
C #:
MSIL:
Saya bukan ahli dalam IL tetapi kita dapat melihat bahwa objek pengecualian lokal dibuat pada baris keempat
.locals init ([0] class [mscorlib]System.Exception ex)
setelah itu semuanya sama seperti untuk metode tanpa mencoba / menangkap sampai baris tujuh belasIL_0021: leave.s IL_002f
. Jika pengecualian terjadi, kontrol akan melompat ke baris,IL_0025: ldloc.0
jika tidak, kita akan beralih ke labelIL_002d: leave.s IL_002f
dan fungsi kembali.Saya dapat dengan aman berasumsi bahwa jika tidak ada pengecualian terjadi maka itu adalah overhead untuk membuat variabel lokal untuk menyimpan objek pengecualian
sajadan instruksi lompat.sumber
Tidak. Jika optimasi sepele blok percobaan / akhirnya menghalangi sebenarnya memiliki dampak yang terukur pada program Anda, Anda mungkin tidak boleh menggunakan .NET di tempat pertama.
sumber
Penjelasan yang cukup komprehensif tentang model pengecualian .NET.
Tidbits Performa Rico Mariani: Biaya Pengecualian: Kapan melempar dan kapan tidak
Dmitriy Zaslavskiy:
sumber
Struktur ini berbeda dalam contoh dari Ben M . Ini akan diperpanjang overhead di dalam
for
loop batin yang akan menyebabkannya menjadi perbandingan yang tidak baik antara dua kasus.Berikut ini lebih akurat untuk perbandingan tempat seluruh kode untuk diperiksa (termasuk deklarasi variabel) di dalam blok Coba / Tangkap:
Ketika saya menjalankan kode tes asli dari Ben M , saya melihat perbedaan dalam konfigurasi Debug dan Releas.
Versi ini, saya perhatikan ada perbedaan dalam versi debug (sebenarnya lebih dari versi lain), tetapi tidak ada perbedaan dalam versi Rilis.
Kesimpulan :
Berdasarkan tes ini, saya pikir kita dapat mengatakan bahwa Try / Catch memang memiliki dampak kecil pada kinerja.
EDIT:
Saya mencoba untuk meningkatkan nilai loop dari 10.000000 ke 1000000000, dan berlari lagi di Rilis untuk mendapatkan beberapa perbedaan dalam rilis, dan hasilnya adalah ini:
Anda melihat bahwa hasilnya tidak sesuai. Dalam beberapa kasus, versi yang menggunakan Try / Catch sebenarnya lebih cepat!
sumber
try/catch
sini. Waktu Anda 12 mencoba / menangkap memasuki-bagian-kritis terhadap 10 juta loop. Kebisingan dari loop akan menghilangkan segala pengaruh try / catch. jika sebaliknya Anda meletakkan try / catch di dalam loop ketat, dan membandingkan dengan / tanpa, Anda akan berakhir dengan biaya try / catch. (tidak diragukan lagi, pengkodean seperti itu umumnya bukan praktik yang baik, tetapi jika Anda ingin menghitung waktu overhead suatu konstruksi, itulah cara Anda melakukannya). Saat ini, BenchmarkDotNet adalah alat bantu untuk waktu eksekusi yang andal.Saya menguji dampak sebenarnya dari
try..catch
lingkaran ketat, dan terlalu kecil untuk menjadi perhatian kinerja dalam situasi normal apa pun.Jika loop tidak banyak bekerja (dalam pengujian saya melakukan
x++
), Anda dapat mengukur dampak penanganan pengecualian. Pengulangan dengan penanganan pengecualian membutuhkan waktu sekitar sepuluh kali lebih lama untuk dijalankan.Jika loop melakukan beberapa pekerjaan yang sebenarnya (dalam pengujian saya, saya disebut metode Int32.Parse), penanganan pengecualian memiliki dampak terlalu kecil untuk dapat diukur. Saya mendapat perbedaan yang jauh lebih besar dengan menukar urutan loop ...
sumber
coba tangkap blok memiliki dampak yang dapat diabaikan pada kinerja tetapi pengecualian Melempar bisa sangat besar, ini mungkin di mana rekan kerja Anda bingung.
sumber
Coba / tangkap HAS berdampak pada kinerja.
Tapi itu bukan dampak yang besar. coba / tangkap kompleksitas umumnya O (1), sama seperti tugas sederhana, kecuali ketika mereka ditempatkan dalam satu lingkaran. Jadi, Anda harus menggunakannya dengan bijak.
Berikut ini adalah referensi tentang kinerja try / catch (tidak menjelaskan kompleksitasnya, tetapi tersirat). Lihatlah Throw sedikit Pengecualian bagian
sumber
Secara teori, blok coba / tangkap tidak akan berpengaruh pada perilaku kode kecuali jika benar-benar terjadi pengecualian. Namun, ada beberapa keadaan yang jarang, di mana keberadaan blok coba / tangkap mungkin memiliki efek besar, dan beberapa yang tidak umum tetapi hampir tidak jelas di mana efeknya dapat terlihat. Alasannya adalah karena kode yang diberikan seperti:
kompiler mungkin dapat mengoptimalkan statement1 berdasarkan pada fakta bahwa statement2 dijamin untuk dieksekusi sebelum statement3. Jika kompilator dapat mengenali bahwa thing1 tidak memiliki efek samping dan thing2 tidak benar-benar menggunakan x, ia dapat dengan aman menghilangkan thing1 sama sekali. Jika [seperti dalam kasus ini] hal1 mahal, itu bisa menjadi optimasi besar, meskipun kasus di mana hal1 mahal juga mereka yang paling tidak mungkin dikompilasi oleh kompiler. Misalkan kode diubah:
Sekarang ada urutan peristiwa di mana statement3 bisa dieksekusi tanpa statement2 dieksekusi. Bahkan jika tidak ada dalam kode untuk
thing2
bisa melempar pengecualian, akan ada kemungkinan bahwa utas lain dapat menggunakanInterlocked.CompareExchange
untuk melihat yangq
telah dihapus dan mengaturnyaThread.ResetAbort
, dan kemudian melakukanThread.Abort()
sebelum statement2 menulis nilainyax
. Makacatch
akan mengeksekusiThread.ResetAbort()
[via delegateq
], yang memungkinkan eksekusi untuk melanjutkan dengan statement3. Urutan peristiwa seperti itu tentu saja sangat tidak mungkin, tetapi kompiler diperlukan untuk menghasilkan kode yang bekerja sesuai dengan spesifikasi bahkan ketika peristiwa yang mustahil terjadi.Secara umum, kompiler jauh lebih mungkin untuk melihat peluang untuk meninggalkan bit kode sederhana daripada yang kompleks, dan dengan demikian akan jarang untuk mencoba / menangkap dapat mempengaruhi kinerja banyak jika pengecualian tidak pernah dibuang. Namun, ada beberapa situasi di mana keberadaan blok coba / tangkap dapat mencegah optimasi yang - tetapi untuk coba / tangkap - akan memungkinkan kode untuk berjalan lebih cepat.
sumber
Meskipun " Pencegahan lebih baik daripada penanganan ", dalam perspektif kinerja dan efisiensi kita bisa memilih try-catch daripada pre-varication. Pertimbangkan kode di bawah ini:
Inilah hasilnya:
sumber
Lihat diskusi tentang implementasi try / catch untuk diskusi tentang cara kerja try / catch blocks, dan bagaimana beberapa implementasi memiliki overhead yang tinggi, dan beberapa memiliki overhead nol, ketika tidak ada pengecualian. Secara khusus, saya pikir implementasi Windows 32 bit memiliki overhead yang tinggi, dan implementasi 64 bit tidak.
sumber