Выполнение try-catch в php - PullRequest
       36

Выполнение try-catch в php

56 голосов
/ 19 сентября 2008

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

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

Ответы [ 8 ]

66 голосов
/ 19 сентября 2008

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

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

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

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

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

52 голосов
/ 15 января 2009

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

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

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

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

18 голосов
/ 16 июля 2013

Блоки 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
8 голосов
/ 19 сентября 2008

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

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

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

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

5 голосов
/ 19 сентября 2008

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

2 голосов
/ 08 октября 2012

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

Я также считаю (не проверено), что:

<?php
//beginning code
try{
    //some more code
    foreach($var as $k=>$v){
        $var[$k] = $v+1;
    }
    //more code
}catch(Exception($e)){
}
//output everything
?>

дороже, чем иметь дополнительные IF в коде

1 голос
/ 03 декабря 2009

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

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

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

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

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

0 голосов
/ 19 сентября 2008

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

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

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

Удачи!

...