Производительность try-catch в php
Какие последствия для производительности следует учитывать при использовании утверждений try-catch в php 5?
Я читал ранее старую и, казалось бы, противоречивую информацию по этому вопросу в Интернете. Большая часть структуры, с которой я в настоящее время работаю, была создана на php 4 и не имеет большого количества тонкостей php 5. Итак, у меня нет большого опыта использования try-catch с php.
Ответы
Ответ 1
Одна вещь, которую следует учитывать, заключается в том, что стоимость блока try, где не генерируется исключение, - это другой вопрос из стоимости фактического броска и обнаружения исключения.
Если исключения случаются только в случаях сбоя, вы почти наверняка не заботитесь о производительности, поскольку вы не будете терпеть неудачу очень много раз за выполнение вашей программы. Если вы терпите неудачу в петле (a.k.a: стучите головой о кирпичную стену), ваше приложение, вероятно, имеет более серьезные проблемы, чем медленное. Поэтому не беспокойтесь о стоимости выброса исключения, если вы каким-то образом не вынуждены использовать их для регулярного потока управления.
Кто-то отправил ответ, говорящий о профилировании кода, который выдает исключение. Я никогда не тестировал его сам, но я уверенно предсказываю, что это будет показывать гораздо больший успех, чем просто входить и выходить из блока try, не бросая ничего.
Еще одна вещь, которую следует учитывать, заключается в том, что там, где вы гнездо называет много уровней, может быть даже быстрее иметь одну попытку... ухватиться правее вверху, чем проверять возвращаемые значения и распространять ошибки при каждом вызове.
В противоположность этой ситуации, когда вы обнаружите, что вы завершаете каждый вызов в своем собственном блоке try... catch, ваш код будет медленнее. И уродливый.
Ответ 2
Мне было скучно и профилировано следующее (я оставил код таймера):
function no_except($a, $b) {
$a += $b;
return $a;
}
function except($a, $b) {
try {
$a += $b;
} catch (Exception $e) {}
return $a;
}
с использованием двух разных циклов:
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) {}
}
С 1000000 запусков в моем поле WinXP запустите apache и 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
Эти результаты были согласованными и оставались в одинаковой пропорции независимо от того, какой заказ выполнялся.
Заключение: добавление кода для обработки редких исключений не медленнее, чем код игнорирует исключения.
Ответ 3
Блоки try-catch не являются проблемой производительности - реальное узкое место производительности происходит от создания объектов исключения.
Тестовый код:
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";
}
Результаты:
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
Ответ 4
Как правило, используйте исключение для защиты от непредвиденных сбоев и используйте проверку ошибок в вашем коде против сбоев, которые являются частью нормального состояния программы. Чтобы проиллюстрировать:
-
Запись не найдена в базе данных - действительное состояние, вы должны проверять результаты запроса и сообщать пользователю надлежащим образом.
-
Ошибка SQL при попытке получить запись - неожиданный сбой, запись может быть или не быть, но у вас есть программная ошибка - это хорошее место для исключения - ошибка журнала в журнале ошибок, электронная почта администратора трассировку стека и показать вежливое сообщение об ошибке пользователю, сообщив ему, что что-то пошло не так, и вы работаете над ним.
Исключения являются дорогостоящими, но если вы не будете обрабатывать весь ваш поток программ, используя их, любая разница в производительности не должна быть заметной для человека.
Ответ 5
Я ничего не нашел в работе Try/Catch в Google, но простой тест с ошибкой металирования цикла вместо оператора IF создает 329ms против 6ms в цикле 5000.
Ответ 6
Извините за сообщение в очень старом сообщении, но я прочитал комментарии, и я несколько не согласен, разница может быть минимальной с простой частью кода, или это может быть пренебрежимо, если Try/Catch используются для определенных частей кода которые не всегда предсказуемы, но я также считаю (не проверял), что простой:
if(isset($var) && is_array($var)){
foreach($var as $k=>$v){
$var[$k] = $v+1;
}
}
быстрее, чем
try{
foreach($var as $k=>$v){
$var[$k] = $v+1;
}
}catch(Exception($e)){
}
Я также считаю (не тестировал), что a:
<?php
//beginning code
try{
//some more code
foreach($var as $k=>$v){
$var[$k] = $v+1;
}
//more code
}catch(Exception($e)){
}
//output everything
?>
дороже, чем дополнительные IF в коде
Ответ 7
Это очень хороший вопрос!
Я тестировал его много раз и никогда не видел проблемы с производительностью;-) Это было правдой 10 лет назад на С++, но я думаю, что сегодня они значительно улучшили его с момента его использования и очистки.
Но я все еще боюсь окружить свою первую точку входа с ним:
try {Controller::run();}catch(...)
Я не тестировал с большим количеством вызовов функций и большого включения.... Кто-нибудь уже полностью его протестировал?
Ответ 8
Вообще говоря, они дороги и не стоят в PHP.
Поскольку это проверенный язык выражений, вы ДОЛЖНЫ улавливать все, что выдает исключение.
При работе с устаревшим кодом, который не бросается, и новым кодом, который это делает, это только приводит к путанице.
Удачи!