ประสิทธิภาพของข้อยกเว้นใน Java และ C # เป็นที่ต้องการอย่างมาก
ในฐานะผู้เขียนโปรแกรมสิ่งนี้บังคับให้เราดำเนินชีวิตตามกฎ "ข้อยกเว้นควรเกิดขึ้นไม่บ่อยนัก" เพียงเพื่อเหตุผลด้านประสิทธิภาพ
อย่างไรก็ตามในฐานะนักวิทยาศาสตร์คอมพิวเตอร์เราควรต่อต้านรัฐบาลที่มีปัญหานี้ คนที่เขียนฟังก์ชั่นมักจะไม่รู้ว่ามันจะถูกเรียกบ่อยแค่ไหนหรือว่าความสำเร็จหรือความล้มเหลวนั้นมีแนวโน้มมากขึ้น มีเพียงผู้โทรเท่านั้นที่มีข้อมูลนี้ การพยายามหลีกเลี่ยงข้อยกเว้นนำไปสู่การที่ไม่ชัดเจนของ API idoms ซึ่งในบางกรณีเรามีเฉพาะรุ่นคลีน แต่ช้ายกเว้นและในกรณีอื่น ๆ เรามีข้อผิดพลาดที่ส่งกลับค่าอย่างรวดเร็ว แต่ไม่น่าสนใจและในกรณีอื่น ๆ . ผู้พัฒนาไลบรารีอาจต้องเขียนและดูแล API สองเวอร์ชันและผู้เรียกต้องตัดสินใจว่าจะใช้สองเวอร์ชันใดในแต่ละสถานการณ์
นี่เป็นระเบียบ หากข้อยกเว้นมีประสิทธิภาพที่ดีขึ้นเราสามารถหลีกเลี่ยงสำนวนที่เป็น clunky เหล่านี้และใช้ข้อยกเว้นตามที่ตั้งใจจะใช้ ... เป็นสิ่งอำนวยความสะดวกในการส่งคืนข้อผิดพลาดแบบมีโครงสร้าง
ฉันอยากเห็นกลไกการยกเว้นที่นำมาใช้โดยใช้เทคนิคที่ใกล้เคียงกับค่าส่งคืนมากขึ้นดังนั้นเราจึงสามารถมีประสิทธิภาพใกล้เคียงกับค่าที่ส่งคืน .. เนื่องจากนี่คือสิ่งที่เราเปลี่ยนกลับไปเป็นรหัสที่ไวต่อประสิทธิภาพ
นี่คือตัวอย่างโค้ดที่เปรียบเทียบประสิทธิภาพข้อยกเว้นกับประสิทธิภาพข้อผิดพลาด - คืน - ค่า
ระดับสาธารณะ TestIt {
int value;
public int getValue() {
return value;
}
public void reset() {
value = 0;
}
public boolean baseline_null(boolean shouldfail, int recurse_depth) {
if (recurse_depth <= 0) {
return shouldfail;
} else {
return baseline_null(shouldfail,recurse_depth-1);
}
}
public boolean retval_error(boolean shouldfail, int recurse_depth) {
if (recurse_depth <= 0) {
if (shouldfail) {
return false;
} else {
return true;
}
} else {
boolean nested_error = retval_error(shouldfail,recurse_depth-1);
if (nested_error) {
return true;
} else {
return false;
}
}
}
public void exception_error(boolean shouldfail, int recurse_depth) throws Exception {
if (recurse_depth <= 0) {
if (shouldfail) {
throw new Exception();
}
} 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 = 100000000;
// (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;
long start_time = System.currentTimeMillis();
t.reset();
for (i = 1; i < ITERATION_COUNT; i++) {
boolean shoulderror = (i % EXCEPTION_MOD) == 0;
t.baseline_null(shoulderror,recurse_depth);
}
long elapsed_time = System.currentTimeMillis() - start_time;
System.out.format("baseline: recurse_depth %s, exception_freqeuncy %s (%s), time elapsed %s ms\n",
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;
long start_time = System.currentTimeMillis();
t.reset();
for (i = 1; i < ITERATION_COUNT; i++) {
boolean shoulderror = (i % EXCEPTION_MOD) == 0;
if (!t.retval_error(shoulderror,recurse_depth)) {
failures++;
}
}
long elapsed_time = System.currentTimeMillis() - start_time;
System.out.format("retval_error: recurse_depth %s, exception_freqeuncy %s (%s), time elapsed %s ms\n",
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;
long start_time = System.currentTimeMillis();
t.reset();
for (i = 1; i < ITERATION_COUNT; i++) {
boolean shoulderror = (i % EXCEPTION_MOD) == 0;
try {
t.exception_error(shoulderror,recurse_depth);
} catch (Exception e) {
failures++;
}
}
long elapsed_time = System.currentTimeMillis() - start_time;
System.out.format("exception_error: recurse_depth %s, exception_freqeuncy %s (%s), time elapsed %s ms\n",
recurse_depth, exception_freq, failures,elapsed_time);
}
}
}
}
และนี่คือผลลัพธ์:
baseline: recurse_depth 2, exception_freqeuncy 0.0 (0), time elapsed 683 ms
baseline: recurse_depth 2, exception_freqeuncy 0.25 (0), time elapsed 790 ms
baseline: recurse_depth 2, exception_freqeuncy 0.5 (0), time elapsed 768 ms
baseline: recurse_depth 2, exception_freqeuncy 0.75 (0), time elapsed 749 ms
baseline: recurse_depth 2, exception_freqeuncy 1.0 (0), time elapsed 731 ms
baseline: recurse_depth 5, exception_freqeuncy 0.0 (0), time elapsed 923 ms
baseline: recurse_depth 5, exception_freqeuncy 0.25 (0), time elapsed 971 ms
baseline: recurse_depth 5, exception_freqeuncy 0.5 (0), time elapsed 982 ms
baseline: recurse_depth 5, exception_freqeuncy 0.75 (0), time elapsed 947 ms
baseline: recurse_depth 5, exception_freqeuncy 1.0 (0), time elapsed 937 ms
baseline: recurse_depth 8, exception_freqeuncy 0.0 (0), time elapsed 1154 ms
baseline: recurse_depth 8, exception_freqeuncy 0.25 (0), time elapsed 1149 ms
baseline: recurse_depth 8, exception_freqeuncy 0.5 (0), time elapsed 1133 ms
baseline: recurse_depth 8, exception_freqeuncy 0.75 (0), time elapsed 1117 ms
baseline: recurse_depth 8, exception_freqeuncy 1.0 (0), time elapsed 1116 ms
retval_error: recurse_depth 2, exception_freqeuncy 0.0 (0), time elapsed 742 ms
retval_error: recurse_depth 2, exception_freqeuncy 0.25 (24999999), time elapsed 743 ms
retval_error: recurse_depth 2, exception_freqeuncy 0.5 (49999999), time elapsed 734 ms
retval_error: recurse_depth 2, exception_freqeuncy 0.75 (99999999), time elapsed 723 ms
retval_error: recurse_depth 2, exception_freqeuncy 1.0 (99999999), time elapsed 728 ms
retval_error: recurse_depth 5, exception_freqeuncy 0.0 (0), time elapsed 920 ms
retval_error: recurse_depth 5, exception_freqeuncy 0.25 (24999999), time elapsed 1121 ms
retval_error: recurse_depth 5, exception_freqeuncy 0.5 (49999999), time elapsed 1037 ms
retval_error: recurse_depth 5, exception_freqeuncy 0.75 (99999999), time elapsed 1141 ms
retval_error: recurse_depth 5, exception_freqeuncy 1.0 (99999999), time elapsed 1130 ms
retval_error: recurse_depth 8, exception_freqeuncy 0.0 (0), time elapsed 1218 ms
retval_error: recurse_depth 8, exception_freqeuncy 0.25 (24999999), time elapsed 1334 ms
retval_error: recurse_depth 8, exception_freqeuncy 0.5 (49999999), time elapsed 1478 ms
retval_error: recurse_depth 8, exception_freqeuncy 0.75 (99999999), time elapsed 1637 ms
retval_error: recurse_depth 8, exception_freqeuncy 1.0 (99999999), time elapsed 1655 ms
exception_error: recurse_depth 2, exception_freqeuncy 0.0 (0), time elapsed 726 ms
exception_error: recurse_depth 2, exception_freqeuncy 0.25 (24999999), time elapsed 17487 ms
exception_error: recurse_depth 2, exception_freqeuncy 0.5 (49999999), time elapsed 33763 ms
exception_error: recurse_depth 2, exception_freqeuncy 0.75 (99999999), time elapsed 67367 ms
exception_error: recurse_depth 2, exception_freqeuncy 1.0 (99999999), time elapsed 66990 ms
exception_error: recurse_depth 5, exception_freqeuncy 0.0 (0), time elapsed 924 ms
exception_error: recurse_depth 5, exception_freqeuncy 0.25 (24999999), time elapsed 23775 ms
exception_error: recurse_depth 5, exception_freqeuncy 0.5 (49999999), time elapsed 46326 ms
exception_error: recurse_depth 5, exception_freqeuncy 0.75 (99999999), time elapsed 91707 ms
exception_error: recurse_depth 5, exception_freqeuncy 1.0 (99999999), time elapsed 91580 ms
exception_error: recurse_depth 8, exception_freqeuncy 0.0 (0), time elapsed 1144 ms
exception_error: recurse_depth 8, exception_freqeuncy 0.25 (24999999), time elapsed 30440 ms
exception_error: recurse_depth 8, exception_freqeuncy 0.5 (49999999), time elapsed 59116 ms
exception_error: recurse_depth 8, exception_freqeuncy 0.75 (99999999), time elapsed 116678 ms
exception_error: recurse_depth 8, exception_freqeuncy 1.0 (99999999), time elapsed 116477 ms
การตรวจสอบและเผยแพร่ค่าตอบแทนจะเพิ่มค่าใช้จ่ายบางอย่างเทียบกับการโทรพื้นฐาน - null และค่าใช้จ่ายนั้นเป็นสัดส่วนกับความลึกการโทร ที่ระดับความลึกสายเรียกเข้า 8 เวอร์ชันการตรวจสอบข้อผิดพลาดคืนค่านั้นช้ากว่ารุ่นพื้นฐานประมาณ 27% ซึ่งไม่ได้ตรวจสอบค่าส่งคืน
ในการเปรียบเทียบข้อยกเว้นไม่ได้เป็นฟังก์ชั่นการโทรเชิงลึก แต่เป็นข้อยกเว้นความถี่ อย่างไรก็ตามการลดลงเมื่อความถี่ในการยกเว้นเพิ่มขึ้นอย่างมาก ที่ความถี่ข้อผิดพลาดเพียง 25% รหัสจะทำงาน 24 ครั้งช้ากว่า ที่ความถี่ข้อผิดพลาด 100% เวอร์ชันยกเว้นจะช้ากว่า 100 ครั้ง
สิ่งนี้ชี้ให้เห็นว่าบางทีฉันอาจทำการค้าผิดในการใช้งานข้อยกเว้นของเรา ข้อยกเว้นอาจเร็วขึ้นไม่ว่าจะด้วยการหลีกเลี่ยงการเดินเล่นแบบราคาแพงหรือเปลี่ยนให้เป็นการตรวจสอบค่าตอบแทนที่สนับสนุนเรียบเรียง เราจะหลีกเลี่ยงพวกเขาเมื่อเราต้องการให้รหัสของเราทำงานเร็ว