Вопрос

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

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

Это было полезно?

Решение

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

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

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

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

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

Другие советы

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

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

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

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

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

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

Я не нашел ничего о производительности Try / Catch в Google, но простой тест с ошибкой запуска цикла вместо оператора IF выдает 329 мс против 6 мс в цикле 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)){
}

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

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

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

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

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

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

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

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

Вообще говоря, они дорогие и не имеют смысла в PHP.

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

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

Удачи вам!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top