Производительность try-catch в php
какие последствия для производительности следует учитывать при использовании операторов try-catch в php 5?
Я читал некоторые старые и, казалось бы, противоречивые сведения по этому вопросу в интернете раньше. Большая часть фреймворка, с которой я сейчас работаю, была создана на php 4 и не имеет многих тонкостей php 5. Так, у меня нет большого опыта в использовании себя попробовать-ловят с PHP.
8 ответов:
одна вещь, которую следует учитывать, заключается в том, что стоимость блока try, в котором не выбрасывается исключение, отличается от стоимости фактического выбрасывания и перехвата исключения.
Если исключения создаются только в случаях сбоя, вы почти наверняка не заботитесь о производительности, так как вы не будете терпеть неудачу очень много раз за выполнение вашей программы. Если вы терпите неудачу в жесткой петле (a.k.a: удар головой о кирпичную стену), ваше приложение, вероятно, имеет худшие проблемы, чем работать медленно. Поэтому не беспокойтесь о стоимости создания исключения, если вы каким-то образом не вынуждены использовать их для регулярного потока управления.
кто-то опубликовал ответ, говорящий о коде профилирования, который вызывает исключение. Я никогда не тестировал его сам, но я уверенно предсказываю, что это покажет гораздо большую производительность, чем просто вход и выход из блока try, ничего не бросая.
еще одна вещь, чтобы рассмотреть, что где вы гнездитесь вызывает много уровней глубоко, это может быть даже быстрее, чтобы иметь одну попытку...поймать прямо в верхней части, чем это проверить возвращаемые значения и распространять ошибки на каждый вызов.
в противоположность этой ситуации, где вы обнаружите, что вы оборачиваете каждый вызов в свою собственную попытку...поймать блок, ваш код будет медленнее. И еще уродливее.
мне было скучно и профилировал следующее (Я оставил код синхронизации):
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 box запустить 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эти результаты были последовательны и оставались в одинаковой пропорции независимо от того, в каком порядке проводились испытания.
вывод: добавление кода для обработки редких исключений не медленнее, чем код игнорирует исключения.
блоки 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
Как правило, используйте исключение для защиты от неожиданных сбоев и используйте проверку ошибок в коде от сбоев, которые являются частью нормального состояния программы. Для иллюстрации:
запись не найдена в базе данных-допустимое состояние, вы должны проверять результаты запроса и сообщения пользователю соответствующим образом.
ошибка SQL при попытке извлечь запись-неожиданный сбой, запись может или не может быть там, но у вас есть ошибка программы - это хорошее место для исключения ошибки в журнале ошибок, напишите администратору трассировку стека и отобразите вежливое сообщение об ошибке пользователю, сообщив ему, что что-то пошло не так, и вы работаете над этим.
исключения стоят дорого, но если вы не обрабатываете весь поток программы, используя их, любая разница в производительности не должна быть заметной для человека.
Я не нашел ничего на Try / Catch производительности на Google, но простой тест с ошибкой цикла метания вместо оператора IF производят 329ms против 6ms в цикле 5000.
Извините, что публикую очень старое сообщение, но я читаю комментарии, и я несколько не согласен, разница может быть минимальной с простым куском кодов, или это может быть пренебрежимо, когда 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 ?>дороже, чем иметь дополнительные IFs в код
Это очень хороший вопрос!
Я тестировал его много раз и никогда не видел никаких проблем с производительностью ;-) это было верно 10 лет назад в C++, но я думаю, что сегодня они улучшили его много, так как его так полезно и чище.
но я все еще боюсь окружить им свою первую точку входа:
try {Controller::run();}catch(...)Я не тестировал с большим количеством функций вызова и большой включить .... Кто-нибудь уже полностью проверил его?
вообще говоря, они дорогие и не стоят в PHP.
Так как это проверенный язык выражений, вы должны поймать все, что вызывает исключение.
при работе с устаревшим кодом, который не бросает, и новым кодом, который делает, это только приводит к путанице.
удачи!
Comments