Pada Windows CLR, untuk rantai panggilan kedalaman-8, melempar pengecualian adalah 750 kali lebih lambat daripada memeriksa dan menyebarkan nilai kembali. (lihat di bawah untuk benchmark)
Biaya pengecualian yang tinggi ini karena windows CLR terintegrasi dengan sesuatu yang disebut Windows Structured Exception Handling . Ini memungkinkan pengecualian untuk ditangkap dan dilempar ke berbagai runtime dan bahasa. Namun, ini sangat lambat.
Pengecualian dalam runtime Mono (pada platform apa pun) jauh lebih cepat, karena tidak terintegrasi dengan SEH. Namun, ada kehilangan fungsionalitas ketika melewati pengecualian di beberapa runtime karena tidak menggunakan apa pun seperti SEH.
Berikut adalah hasil yang disingkat dari patokan pengecualian saya dan nilai pengembalian untuk Windows CLR.
baseline: recurse_depth 8, error_freqeuncy 0 (0), time elapsed 13.0007 ms
baseline: recurse_depth 8, error_freqeuncy 0.25 (0), time elapsed 13.0007 ms
baseline: recurse_depth 8, error_freqeuncy 0.5 (0), time elapsed 13.0008 ms
baseline: recurse_depth 8, error_freqeuncy 0.75 (0), time elapsed 13.0008 ms
baseline: recurse_depth 8, error_freqeuncy 1 (0), time elapsed 14.0008 ms
retval_error: recurse_depth 5, error_freqeuncy 0 (0), time elapsed 13.0008 ms
retval_error: recurse_depth 5, error_freqeuncy 0.25 (249999), time elapsed 14.0008 ms
retval_error: recurse_depth 5, error_freqeuncy 0.5 (499999), time elapsed 16.0009 ms
retval_error: recurse_depth 5, error_freqeuncy 0.75 (999999), time elapsed 16.001 ms
retval_error: recurse_depth 5, error_freqeuncy 1 (999999), time elapsed 16.0009 ms
retval_error: recurse_depth 8, error_freqeuncy 0 (0), time elapsed 20.0011 ms
retval_error: recurse_depth 8, error_freqeuncy 0.25 (249999), time elapsed 21.0012 ms
retval_error: recurse_depth 8, error_freqeuncy 0.5 (499999), time elapsed 24.0014 ms
retval_error: recurse_depth 8, error_freqeuncy 0.75 (999999), time elapsed 24.0014 ms
retval_error: recurse_depth 8, error_freqeuncy 1 (999999), time elapsed 24.0013 ms
exception_error: recurse_depth 8, error_freqeuncy 0 (0), time elapsed 31.0017 ms
exception_error: recurse_depth 8, error_freqeuncy 0.25 (249999), time elapsed 5607.3208 ms
exception_error: recurse_depth 8, error_freqeuncy 0.5 (499999), time elapsed 11172.639 ms
exception_error: recurse_depth 8, error_freqeuncy 0.75 (999999), time elapsed 22297.2753 ms
exception_error: recurse_depth 8, error_freqeuncy 1 (999999), time elapsed 22102.2641 ms
Dan ini kodenya ..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1 {
public class TestIt {
int value;
public class TestException : Exception { }
public int getValue() {
return value;
}
public void reset() {
value = 0;
}
public bool baseline_null(bool shouldfail, int recurse_depth) {
if (recurse_depth <= 0) {
return shouldfail;
} else {
return baseline_null(shouldfail,recurse_depth-1);
}
}
public bool retval_error(bool shouldfail, int recurse_depth) {
if (recurse_depth <= 0) {
if (shouldfail) {
return false;
} else {
return true;
}
} else {
bool nested_error = retval_error(shouldfail,recurse_depth-1);
if (nested_error) {
return true;
} else {
return false;
}
}
}
public void exception_error(bool shouldfail, int recurse_depth) {
if (recurse_depth <= 0) {
if (shouldfail) {
throw new TestException();
}
} else {
exception_error(shouldfail,recurse_depth-1);
}
}
public static void Main(String[] args) {
int i;
long l;
TestIt t = new TestIt();
int failures;
int ITERATION_COUNT = 1000000;
// (0) baseline null workload
for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {
int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);
failures = 0;
DateTime start_time = DateTime.Now;
t.reset();
for (i = 1; i < ITERATION_COUNT; i++) {
bool shoulderror = (i % EXCEPTION_MOD) == 0;
t.baseline_null(shoulderror,recurse_depth);
}
double elapsed_time = (DateTime.Now - start_time).TotalMilliseconds;
Console.WriteLine(
String.Format(
"baseline: recurse_depth {0}, error_freqeuncy {1} ({2}), time elapsed {3} ms",
recurse_depth, exception_freq, failures,elapsed_time));
}
}
// (1) retval_error
for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {
int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);
failures = 0;
DateTime start_time = DateTime.Now;
t.reset();
for (i = 1; i < ITERATION_COUNT; i++) {
bool shoulderror = (i % EXCEPTION_MOD) == 0;
if (!t.retval_error(shoulderror,recurse_depth)) {
failures++;
}
}
double elapsed_time = (DateTime.Now - start_time).TotalMilliseconds;
Console.WriteLine(
String.Format(
"retval_error: recurse_depth {0}, error_freqeuncy {1} ({2}), time elapsed {3} ms",
recurse_depth, exception_freq, failures,elapsed_time));
}
}
// (2) exception_error
for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {
int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);
failures = 0;
DateTime start_time = DateTime.Now;
t.reset();
for (i = 1; i < ITERATION_COUNT; i++) {
bool shoulderror = (i % EXCEPTION_MOD) == 0;
try {
t.exception_error(shoulderror,recurse_depth);
} catch (TestException e) {
failures++;
}
}
double elapsed_time = (DateTime.Now - start_time).TotalMilliseconds;
Console.WriteLine(
String.Format(
"exception_error: recurse_depth {0}, error_freqeuncy {1} ({2}), time elapsed {3} ms",
recurse_depth, exception_freq, failures,elapsed_time)); }
}
}
}
}