[ACCEPTED]-Performance of try-catch in php-try-catch
One thing to consider is that the cost of 27 a try block where no exception is thrown 26 is a different question from the cost of 25 actually throwing and catching an exception.
If 24 exceptions are only thrown in failure cases, you 23 almost certainly don't care about performance, since 22 you won't fail very many times per execution 21 of your program. If you're failing in a 20 tight loop (a.k.a: banging your head against 19 a brick wall), your application likely has 18 worse problems than being slow. So don't 17 worry about the cost of throwing an exception 16 unless you're somehow forced to use them 15 for regular control flow.
Someone posted 14 an answer talking about profiling code which 13 throws an exception. I've never tested it 12 myself, but I confidently predict that this 11 will show a much bigger performance hit 10 than just going in and out of a try block 9 without throwing anything.
Another thing 8 to consider is that where you nest calls 7 a lot of levels deep, it can even be faster 6 to have a single try...catch right at the 5 top than it is to check return values and 4 propagate errors on every call.
In the opposite 3 of that situation, where you find that you're 2 wrapping every call in its own try...catch 1 block, your code will be slower. And uglier.
I was bored and profiled the following (I 7 left the timing code out):
function no_except($a, $b) {
$a += $b;
return $a;
}
function except($a, $b) {
try {
$a += $b;
} catch (Exception $e) {}
return $a;
}
using two different 6 loops:
echo 'no except with no surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
no_except(5, 7);
}
echo 'no except with surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
try {
no_except(5, 7);
} catch (Exception $e) {}
}
echo 'except with no surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
except(5, 7);
}
echo 'except with surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
try {
except(5, 7);
} catch (Exception $e) {}
}
With 1000000 runs on my WinXP box 5 run apache and PHP 5.2.6:
no except with no surrounding try = 3.3296
no except with surrounding try = 3.4246
except with no surrounding try = 3.2548
except with surrounding try = 3.2913
These results were 4 consistent and remained in similar proportion 3 no matter which order the tests ran.
Conclusion: Adding 2 code to handle rare exceptions is no slower 1 than code the ignores exceptions.
Try-catch blocks are not a performance problem 2 - the real performance bottleneck comes 1 from creating exception objects.
Test code:
function shuffle_assoc($array) {
$keys = array_keys($array);
shuffle($keys);
return array_merge(array_flip($keys), $array);
}
$c_e = new Exception('n');
function no_try($a, $b) {
$a = new stdclass;
return $a;
}
function no_except($a, $b) {
try {
$a = new Exception('k');
} catch (Exception $e) {
return $a + $b;
}
return $a;
}
function except($a, $b) {
try {
throw new Exception('k');
} catch (Exception $e) {
return $a + $b;
}
return $a;
}
function constant_except($a, $b) {
global $c_e;
try {
throw $c_e;
} catch (Exception $e) {
return $a + $b;
}
return $a;
}
$tests = array(
'no try with no surrounding try'=>function() {
no_try(5, 7);
},
'no try with surrounding try'=>function() {
try {
no_try(5, 7);
} catch (Exception $e) {}
},
'no except with no surrounding try'=>function() {
no_except(5, 7);
},
'no except with surrounding try'=>function() {
try {
no_except(5, 7);
} catch (Exception $e) {}
},
'except with no surrounding try'=>function() {
except(5, 7);
},
'except with surrounding try'=>function() {
try {
except(5, 7);
} catch (Exception $e) {}
},
'constant except with no surrounding try'=>function() {
constant_except(5, 7);
},
'constant except with surrounding try'=>function() {
try {
constant_except(5, 7);
} catch (Exception $e) {}
},
);
$tests = shuffle_assoc($tests);
foreach($tests as $k=>$f) {
echo $k;
$start = microtime(true);
for ($i = 0; $i < 1000000; ++$i) {
$f();
}
echo ' = '.number_format((microtime(true) - $start), 4)."<br>\n";
}
Results:
no try with no surrounding try = 0.5130
no try with surrounding try = 0.5665
no except with no surrounding try = 3.6469
no except with surrounding try = 3.6979
except with no surrounding try = 3.8729
except with surrounding try = 3.8978
constant except with no surrounding try = 0.5741
constant except with surrounding try = 0.6234
Generally, use an exception to guard against 17 unexpected failures, and use error checking 16 in your code against failures that are part 15 of normal program state. To illustrate:
Record 14 not found in database - valid state, you 13 should be checking the query results and 12 messaging the user appropriately.
SQL error 11 when trying to fetch record - unexpected 10 failure, the record may or may not be there, but 9 you have a program error - this is good 8 place for an exception - log error in error 7 log, email the administrator the stack trace, and 6 display a polite error message to the user 5 advising him that something went wrong and 4 you're working on it.
Exceptions are expensive, but 3 unless you handle your whole program flow 2 using them, any performance difference should 1 not be human-noticeable.
I have not found anything on Try/Catch performance 3 on Google but a simple test with a loop 2 throwing error instead of a IF statement 1 produce 329ms vs 6ms in a loop of 5000.
Sorry to post to a very old message, but 9 I read the comments and I somewhat disagree, the 8 difference might be minimal with simple 7 piece of codes, or it could be neglectable 6 where the Try/Catch are used for specific 5 parts of code that are not always predictable, but 4 I also believe (not tested) that a simple:
if(isset($var) && is_array($var)){
foreach($var as $k=>$v){
$var[$k] = $v+1;
}
}
is 3 faster than
try{
foreach($var as $k=>$v){
$var[$k] = $v+1;
}
}catch(Exception($e)){
}
I also believe (not tested) that 2 a:
<?php
//beginning code
try{
//some more code
foreach($var as $k=>$v){
$var[$k] = $v+1;
}
//more code
}catch(Exception($e)){
}
//output everything
?>
is more expensive than have extra IFs 1 in the code
I updated Brilliand's test code to make 15 it's report more understandable and also 14 statitistically truthfully by adding more 13 randomness. Since I changed some of its 12 tests to make them more fair the results 11 will be different, therefore I write it 10 as different answer.
My tests executed by: PHP 9 7.4.4 (cli) (built: Mar 20 2020 13:47:45) ( NTS 8 )
<?php
function shuffle_assoc($array) {
$keys = array_keys($array);
shuffle($keys);
return array_merge(array_flip($keys), $array);
}
$c_e = new Exception('n');
function do_nothing($a, $b) {
return $a + $b;
}
function new_exception_but_not_throw($a, $b) {
try {
new Exception('k');
} catch (Exception $e) {
return $a + $b;
}
return $a + $b;
}
function new_exception_and_throw($a, $b) {
try {
throw new Exception('k');
} catch (Exception $e) {
return $a + $b;
}
return $a + $b;
}
function constant_exception_and_throw($a, $b) {
global $c_e;
try {
throw $c_e;
} catch (Exception $e) {
return $a + $b;
}
return $a + $b;
}
$tests = array(
'do_nothing with no surrounding try'=>function() {
do_nothing(5, 7);
},
'do_nothing with surrounding try'=>function() {
try {
do_nothing(5, 7);
} catch (Exception $e) {}
},
'new_exception_but_not_throw with no surrounding try'=>function() {
new_exception_but_not_throw(5, 7);
},
'new_exception_but_not_throw with surrounding try'=>function() {
try {
new_exception_but_not_throw(5, 7);
} catch (Exception $e) {}
},
'new_exception_and_throw with no surrounding try'=>function() {
new_exception_and_throw(5, 7);
},
'new_exception_and_throw with surrounding try'=>function() {
try {
new_exception_and_throw(5, 7);
} catch (Exception $e) {}
},
'constant_exception_and_throw with no surrounding try'=>function() {
constant_exception_and_throw(5, 7);
},
'constant_exception_and_throw with surrounding try'=>function() {
try {
constant_exception_and_throw(5, 7);
} catch (Exception $e) {}
},
);
$results = array_fill_keys(array_keys($tests), 0);
$testCount = 30;
const LINE_SEPARATOR = PHP_EOL; //"<br>";
for ($x = 0; $x < $testCount; ++$x) {
if (($testCount-$x) % 5 === 0) {
echo "$x test cycles done so far".LINE_SEPARATOR;
}
$tests = shuffle_assoc($tests);
foreach ($tests as $k => $f) {
$start = microtime(true);
for ($i = 0; $i < 1000000; ++$i) {
$f();
}
$results[$k] += microtime(true) - $start;
}
}
echo LINE_SEPARATOR;
foreach ($results as $type => $result) {
echo $type.' = '.number_format($result/$testCount, 4).LINE_SEPARATOR;
}
The results are following:
do_nothing with no surrounding try = 0.1873
do_nothing with surrounding try = 0.1990
new_exception_but_not_throw with no surrounding try = 1.1046
new_exception_but_not_throw with surrounding try = 1.1079
new_exception_and_throw with no surrounding try = 1.2114
new_exception_and_throw with surrounding try = 1.2208
constant_exception_and_throw with no surrounding try = 0.3214
constant_exception_and_throw with surrounding try = 0.3312
Conclusions 7 are:
- adding extra try-catch adds ~0.01 microsecond per 1000000 iterations
- exception throwing and catching adds ~0.12 microsecond (x12 compared to previous when nothing were thrown and nothing were catched)
- exception creation adds ~0.91 microsecond (x7.6 compared to execution of try-catch mechanism calculated in previous line)
So the most expensive part is exception 6 creation - not the throw-catch mechanism, however 5 latter made this simple routine 2 times 4 slower compared to do_nothing scenarion.
* all 3 measurements in conclusions are rounded 2 and are not pretends to be scientifically 1 accurate.
Thats a very good question!
I have tested 8 it many times and never saw any performance 7 issue ;-) It was true 10 years ago in C++ but 6 I think today they have improved it a lot 5 since its so usefull and cleaner.
But I am 4 still afraid to surround my first entry 3 point with it:
try {Controller::run();}catch(...)
I didnt test with plenty 2 of functions call and big include .... Is 1 anyone has fully test it already?
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.