Berapa overhead sebenarnya dari coba / tangkap di C #?


94

Jadi, saya tahu bahwa coba / tangkap memang menambahkan beberapa overhead dan oleh karena itu bukan cara yang baik untuk mengontrol aliran proses, tetapi dari mana datangnya overhead ini dan apa dampak sebenarnya?

Jawaban:


52

Saya bukan ahli dalam implementasi bahasa (jadi ambillah ini dengan sedikit garam), tapi saya pikir salah satu biaya terbesar adalah melepas tumpukan dan menyimpannya untuk jejak tumpukan. Saya menduga ini hanya terjadi ketika pengecualian dilemparkan (tetapi saya tidak tahu), dan jika demikian, ini akan menjadi biaya tersembunyi berukuran layak setiap kali pengecualian dilemparkan ... jadi tidak seperti Anda hanya melompat dari satu tempat dalam kode ke kode lain, ada banyak hal yang terjadi.

Saya tidak berpikir itu masalah selama Anda menggunakan pengecualian untuk perilaku LUAR BIASA (jadi bukan jalur yang biasa Anda harapkan melalui program).


33
Lebih tepatnya: usaha itu murah, hasil tangkapan murah, lemparan mahal. Jika Anda menghindari try and catch, melempar masih mahal.
Pemrogram Windows

4
Hmmm - mark-up tidak berfungsi di komentar. Untuk mencoba lagi - pengecualian untuk kesalahan, bukan untuk "perilaku luar biasa" atau kondisi: blogs.msdn.com/kcwalina/archive/2008/07/17/…
HTTP 410

2
@Stats pemrogram Windows / sumber tolong?
Kapé

100

Tiga poin yang harus dibuat di sini:

  • Pertama, ada sedikit atau TIDAK ada penalti kinerja dalam benar-benar memiliki blok coba-tangkap dalam kode Anda. Ini seharusnya tidak menjadi pertimbangan ketika mencoba untuk menghindari mereka dalam aplikasi Anda. Hit kinerja hanya mulai berlaku jika pengecualian dilemparkan.

  • Ketika pengecualian dilemparkan selain operasi pelepasan tumpukan dll yang terjadi yang telah disebutkan orang lain, Anda harus menyadari bahwa sejumlah besar hal-hal yang terkait dengan runtime / refleksi terjadi untuk mengisi anggota kelas pengecualian seperti pelacakan tumpukan objek dan berbagai tipe anggota dll.

  • Saya percaya bahwa ini adalah salah satu alasan mengapa saran umum jika Anda akan memunculkan kembali pengecualian adalah hanya throw;daripada membuang pengecualian lagi atau membuat yang baru karena dalam kasus-kasus itu semua informasi tumpukan itu dikumpulkan kembali sedangkan dalam sederhana membuang itu semua diawetkan.


41
Selain itu: Saat Anda menampilkan kembali pengecualian sebagai "throw ex", Anda akan kehilangan pelacakan tumpukan asli dan menggantinya dengan pelacakan tumpukan SAAT INI; jarang yang diinginkan. Jika Anda hanya "melempar" maka pelacakan tumpukan asli di Pengecualian dipertahankan.
Eddie

@Eddie Atauthrow new Exception("Wrapping layer’s error", ex);
Binki

21

Apakah Anda bertanya tentang overhead menggunakan coba / tangkap / akhirnya ketika pengecualian tidak dilemparkan, atau overhead menggunakan pengecualian untuk mengontrol aliran proses? Yang terakhir ini agak mirip dengan menggunakan dinamit untuk menyalakan lilin ulang tahun balita, dan overhead yang terkait jatuh ke dalam area berikut:

  • Anda dapat mengharapkan kehilangan cache tambahan karena pengecualian yang dilemparkan yang mengakses data penduduk biasanya tidak dalam cache.
  • Anda dapat mengharapkan kesalahan halaman tambahan karena pengecualian yang diberikan mengakses kode non-residen dan data biasanya tidak ada dalam set kerja aplikasi Anda.

    • misalnya, melempar pengecualian akan membutuhkan CLR untuk menemukan lokasi blok last dan catch berdasarkan IP saat ini dan IP kembalian setiap frame hingga pengecualian ditangani ditambah blok filter.
    • biaya konstruksi tambahan dan resolusi nama untuk membuat bingkai untuk tujuan diagnostik, termasuk membaca metadata, dll.
    • kedua item di atas biasanya mengakses kode dan data "dingin", jadi kesalahan halaman keras mungkin terjadi jika Anda memiliki tekanan memori sama sekali:

      • CLR mencoba untuk menempatkan kode dan data yang jarang digunakan jauh dari data yang sering digunakan untuk meningkatkan lokalitas, jadi ini bekerja melawan Anda karena Anda memaksa dingin menjadi panas.
      • biaya kesalahan hard page, jika ada, akan mengerdilkan segalanya.
  • Biasanya situasi tangkapan sering dalam, oleh karena itu efek di atas akan cenderung diperbesar (meningkatkan kemungkinan kesalahan halaman).

Adapun dampak biaya yang sebenarnya, ini dapat sangat bervariasi tergantung pada apa lagi yang terjadi dalam kode Anda saat itu. Jon Skeet memiliki ringkasan yang bagus di sini , dengan beberapa tautan berguna. Saya cenderung setuju dengan pernyataannya bahwa jika Anda sampai pada titik di mana pengecualian secara signifikan mengganggu kinerja Anda, Anda memiliki masalah dalam hal penggunaan pengecualian di luar kinerja.


6

Dalam pengalaman saya, overhead terbesar sebenarnya adalah melakukan pengecualian dan menanganinya. Saya pernah mengerjakan proyek di mana kode yang mirip dengan berikut ini digunakan untuk memeriksa apakah seseorang memiliki hak untuk mengedit beberapa objek. Metode HasRight () ini digunakan di mana saja di lapisan presentasi, dan sering dipanggil untuk 100 objek.

bool HasRight(string rightName, DomainObject obj) {
  try {
    CheckRight(rightName, obj);
    return true;
  }
  catch (Exception ex) {
    return false;
  }
}

void CheckRight(string rightName, DomainObject obj) {
  if (!_user.Rights.Contains(rightName))
    throw new Exception();
}

Ketika database pengujian menjadi lebih penuh dengan data pengujian, ini menyebabkan perlambatan yang sangat terlihat saat membuka formulir baru, dll.

Jadi saya memfaktorkan ulangnya menjadi yang berikut, yang - menurut pengukuran cepat dan kotor - sekitar 2 kali lipat lebih cepat:

bool HasRight(string rightName, DomainObject obj) {
  return _user.Rights.Contains(rightName);
}

void CheckRight(string rightName, DomainObject obj) {
  if (!HasRight(rightName, obj))
    throw new Exception();
}

Jadi singkatnya, menggunakan pengecualian dalam aliran proses normal adalah sekitar dua kali lipat lebih lambat daripada menggunakan aliran proses serupa tanpa pengecualian.


1
Mengapa Anda ingin membuat pengecualian di sini? Anda dapat menangani kasus tidak memiliki hak di tempat.
ThunderGr

@ThunderGr sebenarnya itulah yang saya ubah, menjadikannya dua kali lipat lebih cepat.
Tobi

5

Bertentangan dengan teori yang diterima secara umum, try/ catchdapat memiliki implikasi kinerja yang signifikan, dan terlepas dari apakah pengecualian dilemparkan atau tidak!

  1. Ini menonaktifkan beberapa pengoptimalan otomatis (berdasarkan desain) , dan dalam beberapa kasus memasukkan kode debugging , seperti yang Anda harapkan dari bantuan debugging . Akan selalu ada orang yang tidak setuju dengan saya tentang hal ini, tetapi bahasa membutuhkannya dan pembongkaran menunjukkannya sehingga orang-orang itu menurut kamus definisi delusi .
  2. Ini dapat berdampak negatif pada pemeliharaan. Ini sebenarnya masalah yang paling signifikan di sini, tetapi karena jawaban terakhir saya (yang hampir seluruhnya berfokus padanya) telah dihapus, saya akan mencoba untuk fokus pada masalah yang kurang signifikan (pengoptimalan mikro) daripada masalah yang lebih signifikan ( pengoptimalan makro).

Yang pertama telah tercakup dalam beberapa posting blog oleh Microsoft MVP selama bertahun-tahun, dan saya percaya Anda dapat menemukannya dengan mudah namun StackOverflow sangat peduli dengan konten jadi saya akan memberikan tautan ke beberapa di antaranya sebagai bukti pengisi :

  • Implikasi kinerja try/ catch/finally ( dan bagian dua ), oleh Peter Ritchie mengeksplorasi pengoptimalan yangtry/catch/finallymenonaktifkan (dan saya akan membahas lebih jauh ini dengan kutipan dari standar)
  • Performance Profiling Parsevs. TryParsevs.ConvertTo oleh Ian Huff menyatakan secara terang-terangan bahwa "penanganan pengecualian sangat lambat" dan menunjukkan hal ini dengan mengadu dombaInt.ParsedanInt.TryParsemelawan satu sama lain ... Bagi siapa pun yang bersikeras bahwaTryParsemenggunakantry/ dicatchbelakang layar, ini harus menjelaskan!

Ada juga jawaban ini yang menunjukkan perbedaan antara kode yang dibongkar dengan- dan tanpa menggunakan try/catch .

Tampaknya begitu jelas bahwa ada adalah overhead yang terang-terangan diamati dalam pembuatan kode, dan overhead yang bahkan tampaknya akan diakui oleh orang-orang yang nilai Microsoft! Namun saya, mengulangi internet ...

Ya, ada lusinan instruksi MSIL tambahan untuk satu baris kode yang sepele, dan itu bahkan tidak mencakup pengoptimalan yang dinonaktifkan jadi secara teknis ini adalah pengoptimalan mikro.


Saya memposting jawaban bertahun-tahun yang lalu yang dihapus karena berfokus pada produktivitas pemrogram (pengoptimalan makro).

Hal ini sangat disayangkan karena tidak adanya penghematan beberapa nanodetik di sana-sini waktu CPU kemungkinan akan menutupi banyak jam akumulasi pengoptimalan manual oleh manusia. Mana yang dibayar bos Anda lebih: satu jam waktu Anda, atau satu jam dengan komputer berjalan? Pada titik manakah kita menarik steker dan mengakui bahwa sudah waktunya untuk membeli komputer yang lebih cepat ?

Jelas, prioritas kita harus dioptimalkan , bukan hanya kode kita! Dalam jawaban terakhir saya, saya memanfaatkan perbedaan antara dua potongan kode.

Menggunakan try/ catch:

int x;
try {
    x = int.Parse("1234");
}
catch {
    return;
}
// some more code here...

Tidak menggunakan try/ catch:

int x;
if (int.TryParse("1234", out x) == false) {
    return;
}
// some more code here

Pertimbangkan dari perspektif pengembang pemeliharaan, yang lebih cenderung membuang-buang waktu Anda, jika tidak dalam pembuatan profil / pengoptimalan (dibahas di atas) yang mungkin tidak akan diperlukan jika bukan karena try/ catchmasalah, kemudian dalam menggulir kode sumber ... Salah satunya memiliki empat baris tambahan sampah boilerplate!

Karena semakin banyak kolom yang diperkenalkan ke dalam sebuah kelas, semua sampah boilerplate ini terakumulasi (baik dalam kode sumber maupun kode yang dibongkar) jauh melampaui level yang wajar. Empat baris tambahan per bidang, dan baris itu selalu sama ... Bukankah kita diajari untuk menghindari pengulangan diri kita sendiri? Saya kira kita bisa menyembunyikan try/ di catchbelakang beberapa abstraksi buatan sendiri, tapi ... maka kita sebaiknya menghindari pengecualian (yaitu menggunakanInt.TryParse ).

Ini bahkan bukan contoh yang rumit; Saya telah melihat upaya untuk membuat contoh kelas baru di try/ catch. Pertimbangkan bahwa semua kode di dalam konstruktor mungkin kemudian didiskualifikasi dari pengoptimalan tertentu yang sebaliknya akan diterapkan secara otomatis oleh kompilator. Cara apa yang lebih baik untuk memunculkan teori bahwa kompilator lambat , dibandingkan dengan kompilator adalah melakukan persis seperti yang diperintahkan ?

Dengan asumsi pengecualian dilemparkan oleh konstruktor tersebut, dan beberapa bug dipicu sebagai hasilnya, pengembang pemeliharaan yang buruk kemudian harus melacaknya. Itu mungkin bukan tugas yang mudah, tidak seperti kode spageti dari mimpi buruk goto , try/ catchdapat menyebabkan kekacauan dalam tiga dimensi , karena dapat meningkatkan tumpukan tidak hanya ke bagian lain dari metode yang sama, tetapi juga kelas dan metode lain , yang semuanya akan diamati oleh pengembang pemeliharaan, dengan cara yang sulit ! Namun kami diberitahu bahwa "pergi itu berbahaya", heh!

Di akhir saya menyebutkan, try / catchmemiliki manfaatnya yaitu, ini dirancang untuk menonaktifkan pengoptimalan ! Ini, jika Anda mau, bantuan debugging ! Untuk itulah ia dirancang dan untuk itulah ia harus digunakan sebagai ...

Saya rasa itu juga poin positif. Ini dapat digunakan untuk menonaktifkan pengoptimalan yang mungkin dapat melumpuhkan algoritme penyampaian pesan yang aman dan waras untuk aplikasi multithread, dan untuk menangkap kemungkinan kondisi balapan;) Itulah satu-satunya skenario yang dapat saya pikirkan untuk menggunakan coba / tangkap. Bahkan itu punya alternatif.


Pengoptimalan apa try , catchdan finallynonaktifkan?

AKA

Bagaimana kabarnya try , catchdan finallyberguna sebagai alat bantu debugging?

mereka menulis-hambatan. Ini berasal dari standar:

12.3.3.13 Pernyataan coba-tangkap

Untuk pernyataan stmt dalam bentuk:

try try-block
catch ( ... ) catch-block-1
... 
catch ( ... ) catch-block-n
  • Keadaan penugasan pasti v di awal blok percobaan sama dengan status penugasan pasti v di awal stmt .
  • Keadaan penugasan pasti v di awal catch-block-i (untuk sembarang i ) sama dengan status penetapan pasti v di awal stmt .
  • Keadaan penugasan pasti v pada titik akhir stmt pasti ditetapkan jika (dan hanya jika) v pasti ditetapkan pada titik akhir blok percobaan dan setiap blok-tangkap-i (untuk setiap i dari 1 hingga n ).

Dengan kata lain, di awal masing-masing try pernyataan:

  • semua tugas yang dibuat untuk objek yang terlihat sebelum memasuki try pernyataan harus diselesaikan, yang memerlukan kunci utas sebagai permulaan, sehingga berguna untuk men-debug kondisi balapan!
  • kompilator tidak diperbolehkan untuk:
    • menghilangkan tugas variabel yang tidak digunakan yang pasti telah ditugaskan sebelum try pernyataan
    • mengatur ulang atau menggabungkan semua itu tugas dalamnya (yaitu lihat tautan pertama saya, jika Anda belum melakukannya).
    • mengangkat tugas ke atas penghalang ini, untuk menunda tugas ke variabel yang diketahui tidak akan digunakan sampai nanti (jika sama sekali) atau untuk terlebih dahulu memindahkan tugas selanjutnya ke depan untuk membuat optimisasi lain mungkin ...

Cerita serupa berlaku untuk setiap catchpernyataan; misalkan dalam trypernyataan Anda (atau konstruktor atau fungsi yang dipanggil, dll.) Anda tetapkan ke variabel yang tidak berguna itu (katakanlah, garbage=42;), kompilator tidak dapat menghilangkan pernyataan itu, tidak peduli betapa tidak relevannya itu dengan perilaku program yang dapat diamati . Tugas harus diselesaikan sebelumcatch blok dimasukkan.

Untuk apa nilainya, finallymenceritakan sama merendahkan kisah yang :

12.3.3.14 Pernyataan coba-akhirnya

Untuk mencoba pernyataan stmt dalam bentuk:

try try-block
finally finally-block

• Status tugas pasti v di awal blok percobaan sama dengan status penetapan pasti v di awal stmt .
• Status tugas pasti v di awal blok akhir sama dengan status tugas pasti v di awal stmt .
• Status penetapan pasti v pada titik akhir stmt pasti ditetapkan jika (dan hanya jika) salah satu: o v pasti ditetapkan pada titik akhir blok percobaan o vpasti ditugaskan di titik akhir blok terakhir Jika transfer aliran kontrol (seperti pernyataan goto ) dibuat yang dimulai dalam blok percobaan , dan berakhir di luar blok percobaan , maka v juga dianggap pasti ditugaskan pada itu transfer aliran kontrol jika v pasti ditetapkan pada titik akhir blok akhir . (Ini bukan hanya jika — jika v pasti ditetapkan karena alasan lain pada transfer aliran kontrol ini, maka itu masih dianggap pasti ditetapkan.)

12.3.3.15 Pernyataan coba-tangkap-akhirnya

Analisis tugas pasti untuk pernyataan try - catch - akhirnya dalam bentuk:

try try-block
catch ( ... ) catch-block-1
... 
catch ( ... ) catch-block-n
finally finally-block

dilakukan seolah-olah pernyataan itu adalah percobaan - akhirnya pernyataan yang menyertakan pernyataan coba - tangkap :

try { 
    try   
    try-block
    catch ( ... ) catch-block-1
    ...   
    catch ( ... ) catch-block-n
} 
finally finally-block

3

Belum lagi jika itu di dalam metode yang sering disebut itu dapat mempengaruhi perilaku aplikasi secara keseluruhan.
Sebagai contoh, saya menganggap penggunaan Int32.Parse sebagai praktik yang buruk dalam banyak kasus karena ia memberikan pengecualian untuk sesuatu yang dapat ditangkap dengan mudah jika tidak.

Jadi untuk menyimpulkan semua yang tertulis di sini:
1) Gunakan blok try..catch untuk menangkap kesalahan tak terduga - hampir tidak ada penalti kinerja.
2) Jangan gunakan pengecualian untuk kesalahan yang dikecualikan jika Anda dapat menghindarinya.


3

Saya menulis artikel tentang ini beberapa waktu yang lalu karena ada banyak orang yang menanyakan hal ini pada saat itu. Anda dapat menemukannya dan kode uji di http://www.blackwasp.co.uk/SpeedTestTryCatch.aspx .

Hasilnya adalah bahwa ada sejumlah kecil overhead untuk blok coba / tangkap tetapi sangat kecil sehingga harus diabaikan. Namun, jika Anda menjalankan blok coba / tangkap dalam loop yang dieksekusi jutaan kali, Anda mungkin ingin mempertimbangkan untuk memindahkan blok ke luar loop jika memungkinkan.

Masalah kinerja utama dengan blok coba / tangkap adalah ketika Anda benar-benar menangkap pengecualian. Ini dapat menambah penundaan yang nyata pada aplikasi Anda. Tentu saja, ketika ada yang tidak beres, sebagian besar pengembang (dan banyak pengguna) mengenali jeda sebagai pengecualian yang akan terjadi! Kuncinya di sini bukanlah menggunakan penanganan pengecualian untuk operasi normal. Seperti namanya, mereka luar biasa dan Anda harus melakukan apa saja untuk menghindari mereka terlempar. Anda tidak boleh menggunakannya sebagai bagian dari aliran yang diharapkan dari program yang berfungsi dengan benar.


2

Saya membuat entri blog tentang subjek ini tahun lalu. Saksikan berikut ini. Intinya adalah bahwa hampir tidak ada biaya untuk blok percobaan jika tidak ada pengecualian - dan di laptop saya, pengecualian adalah sekitar 36μs. Itu mungkin kurang dari yang Anda harapkan, tetapi perlu diingat bahwa hasil tersebut berada di tumpukan yang dangkal. Juga, pengecualian pertama sangat lambat.


Saya tidak bisa menjangkau blog Anda (waktu koneksi habis; apakah Anda menggunakan try/ catchterlalu banyak? Heh heh), tetapi Anda tampaknya berdebat dengan spesifikasi bahasa dan beberapa MS MVP yang juga menulis blog tentang subjek tersebut, memberikan pengukuran bertentangan dengan saran Anda ... Saya terbuka untuk saran bahwa penelitian yang telah saya lakukan salah, tetapi saya perlu membaca entri blog Anda untuk melihat apa yang dikatakan.
autis

Selain entri blog @ Hafthor, berikut ini entri blog lain dengan kode yang ditulis khusus untuk menguji perbedaan performa kecepatan. Menurut hasil, jika Anda memiliki pengecualian yang terjadi bahkan hanya 5% dari waktu, kode Penanganan Pengecualian berjalan 100x lebih lambat secara keseluruhan daripada kode penanganan non-pengecualian. Artikel tersebut secara khusus menargetkantry-catch blok vs tryparse(), tetapi konsepnya sama.

2

Jauh lebih mudah untuk menulis, men-debug, dan memelihara kode yang bebas dari pesan kesalahan compiler, pesan peringatan analisis kode, dan pengecualian rutin yang diterima (terutama pengecualian yang dilemparkan di satu tempat dan diterima di tempat lain). Karena lebih mudah, kode rata-rata akan lebih baik ditulis dan lebih sedikit buggy.

Bagi saya, programmer dan overhead kualitas itu adalah argumen utama yang menentang penggunaan try-catch untuk aliran proses.

Pengecualian overhead komputer tidak signifikan jika dibandingkan, dan biasanya kecil dalam hal kemampuan aplikasi untuk memenuhi persyaratan kinerja dunia nyata.


@Ritchard T, kenapa? Dibandingkan dengan programmer dan overhead kualitas itu tidak signifikan.
ThunderGr

1

Saya sangat suka postingan blog Hafthor , dan untuk menambahkan dua sen saya ke diskusi ini, saya ingin mengatakan bahwa, selalu mudah bagi saya untuk membuat LAPISAN DATA hanya melemparkan satu jenis pengecualian (DataAccessException). Dengan cara ini LAPISAN BISNIS saya tahu pengecualian apa yang diharapkan dan menangkapnya. Kemudian bergantung pada aturan bisnis lebih lanjut (yaitu jika objek bisnis saya berpartisipasi dalam alur kerja, dll.), Saya dapat membuat pengecualian baru (BusinessObjectException) atau melanjutkan tanpa mengulang / membuang.

Saya akan mengatakan jangan ragu untuk menggunakan try..catch kapan pun diperlukan dan gunakan dengan bijak!

Misalnya, metode ini berpartisipasi dalam alur kerja ...

Komentar?

public bool DeleteGallery(int id)
{
    try
    {
        using (var transaction = new DbTransactionManager())
        {
            try
            {
                transaction.BeginTransaction();

                _galleryRepository.DeleteGallery(id, transaction);
                _galleryRepository.DeletePictures(id, transaction);

                FileManager.DeleteAll(id);

                transaction.Commit();
            }
            catch (DataAccessException ex)
            {
                Logger.Log(ex);
                transaction.Rollback();                        
                throw new BusinessObjectException("Cannot delete gallery. Ensure business rules and try again.", ex);
            }
        }
    }
    catch (DbTransactionException ex)
    {
        Logger.Log(ex);
        throw new BusinessObjectException("Cannot delete gallery.", ex);
    }
    return true;
}

2
David, maukah Anda menyelesaikan panggilan ke 'DeleteGallery' dalam blok coba / tangkap?
Rob

Karena DeleteGallery adalah fungsi Boolean, bagi saya tampaknya membuang pengecualian di sana tidak berguna. Ini akan membutuhkan panggilan ke DeleteGallery untuk dimasukkan dalam blok coba / tangkap. Sebuah if (! DeleteGallery (theid)) {// handle} terlihat lebih berarti bagi saya. dalam contoh khusus itu.
ThunderGr

1

Kita dapat membaca di Programming Languages ​​Pragmatics oleh Michael L. Scott bahwa kompiler saat ini tidak menambahkan overhead apapun dalam kasus umum, ini berarti, ketika tidak ada pengecualian. Jadi setiap pekerjaan dibuat dalam waktu kompilasi. Tetapi ketika pengecualian dilemparkan pada waktu proses, kompilator perlu melakukan pencarian biner untuk menemukan pengecualian yang benar dan ini akan terjadi untuk setiap lemparan baru yang Anda buat.

Tetapi pengecualian adalah pengecualian dan biaya ini dapat diterima. Jika Anda mencoba melakukan Penanganan Pengecualian tanpa pengecualian dan menggunakan kode kesalahan pengembalian, mungkin Anda akan memerlukan pernyataan if untuk setiap subrutin dan ini akan menimbulkan overhead waktu nyata. Anda tahu jika pernyataan diubah menjadi beberapa instruksi perakitan, yang akan dilakukan setiap kali Anda memasukkan sub-rutin Anda.

Maaf tentang bahasa Inggris saya, semoga dapat membantu Anda. Informasi ini berdasarkan pada buku yang dikutip, untuk informasi lebih lanjut lihat Bab 8.5 Penanganan Pengecualian.


Kompiler keluar dari gambar saat runtime. Ada harus menjadi overhead untuk mencoba / menangkap blok sehingga CLR dapat menangani pengecualian. C # berjalan di .NET CLR (mesin virtual). Tampak bagi saya bahwa overhead blok itu sendiri minimal bila tidak ada pengecualian tetapi biaya penanganan CLR pengecualian sangat signifikan.
ThunderGr

-4

Mari kita analisis salah satu kemungkinan biaya terbesar dari blok coba / tangkap saat digunakan di tempat yang seharusnya tidak perlu digunakan:

int x;
try {
    x = int.Parse("1234");
}
catch {
    return;
}
// some more code here...

Dan inilah yang tanpa coba / tangkap:

int x;
if (int.TryParse("1234", out x) == false) {
    return;
}
// some more code here

Tidak menghitung white-space yang tidak signifikan, orang mungkin memperhatikan bahwa kedua potongan kode yang sama ini hampir sama panjangnya dalam byte. Yang terakhir berisi lekukan 4 byte lebih sedikit. Itu adalah hal yang buruk?

Untuk menambahkan penghinaan pada cedera, seorang siswa memutuskan untuk mengulang sementara input dapat diuraikan sebagai int. Solusi tanpa coba / tangkap mungkin seperti ini:

while (int.TryParse(...))
{
    ...
}

Tapi bagaimana tampilannya saat menggunakan try / catch?

try {
    for (;;)
    {
        x = int.Parse(...);
        ...
    }
}
catch
{
    ...
}

Blok coba / tangkap adalah cara ajaib untuk membuang-buang lekukan, dan kita masih belum tahu alasan kegagalannya! Bayangkan bagaimana perasaan orang yang melakukan debugging, ketika kode terus dieksekusi melewati cacat logis yang serius, daripada berhenti dengan kesalahan pengecualian yang jelas dan bagus. Blok coba / tangkap adalah validasi / sanitasi data orang malas.

Salah satu biaya yang lebih kecil adalah bahwa blok coba / tangkap memang menonaktifkan pengoptimalan tertentu: http://msmvps.com/blogs/peterritchie/archive/2007/06/22/performance-implications-of-try-catch-finally.aspx . Saya rasa itu juga poin positif. Ini dapat digunakan untuk menonaktifkan pengoptimalan yang mungkin dapat melumpuhkan algoritma penyampaian pesan yang aman dan waras untuk aplikasi multithread, dan untuk menangkap kemungkinan kondisi balapan;) Itulah satu-satunya skenario yang dapat saya pikirkan untuk menggunakan coba / tangkap. Bahkan itu punya alternatif.


1
Saya cukup yakin bahwa TryParse melakukan percobaan {int x = int.Parse ("xxx"); return true;} catch {return false; } secara internal. Indentasi bukanlah perhatian dalam pertanyaan, hanya kinerja dan overhead.
ThunderGr

@ThunderGr Atau, baca jawaban baru yang saya posting. Ini berisi banyak link, salah satunya adalah analisis meningkatkan kinerja besar ketika Anda menghindari Int.Parsemendukung Int.TryParse.
autis
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.