Производительность try-catch в php


Какие последствия для производительности следует учитывать при использовании операторов try-catch в php 5?

Я уже читал в Интернете кое-какую старую и, казалось бы, противоречивую информацию по этому вопросу. Большая часть фреймворка, с которым мне в настоящее время приходится работать, была создана на php 4 и лишена многих тонкостей php 5. Таким образом, у меня самого нет большого опыта в использовании try-catchs с php.

Author: Travis, 2008-09-19

8 answers

Следует учитывать, что стоимость блока try, в котором не создается исключение, отличается от стоимости фактического создания и перехвата исключения.

Если исключения возникают только в случаях сбоя, вы почти наверняка не заботитесь о производительности, так как вы не будете терпеть неудачу очень много раз за выполнение своей программы. Если вы терпите неудачу в узком цикле (он же: бьетесь головой о кирпичную стену), у вашего приложения, вероятно, есть проблемы похуже, чем быть медленный. Так что не беспокойтесь о стоимости создания исключения, если только вы каким-то образом не вынуждены использовать их для регулярного потока управления.

Кто-то опубликовал ответ, в котором говорится о коде профилирования, который создает исключение. Я никогда не тестировал это сам, но я с уверенностью предсказываю, что это покажет гораздо больший эффект производительности, чем просто вход и выход из блока попыток, ничего не бросая.

Еще одна вещь, которую следует учитывать, заключается в том, что там, где вы гнездитесь, есть много глубоких уровней, это может быть даже быстрее сделать одну попытку... поймать прямо вверху, чем проверять возвращаемые значения и распространять ошибки при каждом вызове.

В противоположной ситуации, когда вы обнаруживаете, что каждый вызов оборачивается в отдельный блок try...catch, ваш код будет работать медленнее. И еще уродливее.

 63
Author: Steve Jessop, 2008-09-20 15:21:05

Мне было скучно, и я описал следующее (я не указал код времени):

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

Эти результаты были последовательными и оставались в одинаковой пропорции независимо от того, в каком порядке проводились тесты.

Вывод: Добавление кода для обработки редких исключений происходит не медленнее, чем код, игнорирующий исключения.

 49
Author: jmucchiello, 2009-07-21 09:27:49

Блоки 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
 18
Author: Brilliand, 2013-07-16 19:07:25

Как правило, используйте исключение для защиты от неожиданных сбоев и используйте проверку ошибок в своем коде для предотвращения сбоев, которые являются частью нормального состояния программы. Для иллюстрации:

  1. Запись не найдена в состоянии, допустимом для базы данных, вы должны проверять результаты запроса и соответствующим образом отправлять сообщения пользователю.

  2. Ошибка SQL при попытке извлечь запись - неожиданный сбой, запись может быть там, а может и не быть, но у вас ошибка программы - это хорошее место для исключения ошибки в журнале ошибок отправьте администратору по электронной почте трассировку стека и отобразите вежливое сообщение об ошибке пользователю, сообщающее ему, что что-то пошло не так, и вы работаете над этим.

Исключения стоят дорого, но если вы не обрабатываете весь программный поток с их помощью, любая разница в производительности не должна быть заметной для человека.

 8
Author: Aeon, 2008-09-19 18:51:20

Я не нашел ничего о производительности Try/Catch в Google, кроме простого теста с ошибкой запуска цикла вместо оператора IF, который выдает 329 мс против 6 мс в цикле 5000.

 5
Author: Patrick Desjardins, 2008-09-19 18:35:45

Извините, что публикую очень старое сообщение, но я прочитал комментарии, и я несколько не согласен, разница может быть минимальной с простым фрагментом кода, или ею можно пренебречь, когда 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 в коде

 2
Author: Fabrizio, 2012-10-08 16:29:07

Это очень хороший вопрос!

Я тестировал его много раз и никогда не видел никаких проблем с производительностью;-) Это было верно 10 лет назад в C++, но я думаю, что сегодня они значительно улучшили его, так как он такой полезный и чистый.

Но я все еще боюсь окружить им свою первую точку входа:

try {Controller::run();}catch(...)

Я не тестировал с большим количеством функций call и big include.... Кто-нибудь уже полностью протестировал его?

 1
Author: Tom, 2009-12-03 11:43:34

Вообще говоря, они дороги и не стоят в PHP.

Поскольку это проверяемый язык выражений, вы ДОЛЖНЫ перехватывать все, что создает исключение.

Когда имеешь дело с устаревшим кодом, который не выбрасывается, и новым кодом, который это делает, это приводит только к путанице.

Удачи!

 -8
Author: Ian P, 2008-09-19 18:31:57