Rendimiento de try-catch en php


¿Qué tipo de implicaciones de rendimiento hay que considerar cuando se utilizan sentencias try-catch en php 5?

He leído alguna información antigua y aparentemente contradictoria sobre este tema en la web antes. Gran parte del framework con el que actualmente tengo que trabajar fue creado en php 4 y carece de muchas de las sutilezas de php 5. Por lo tanto, no tengo mucha experiencia en el uso de try-catchs con php.

Author: Travis, 2008-09-19

8 answers

Una cosa a considerar es que el costo de un bloque de prueba donde no se lanza ninguna excepción es una pregunta diferente del costo de lanzar y atrapar una excepción.

Si las excepciones solo se lanzan en casos de error, es casi seguro que no le importa el rendimiento, ya que no fallará muchas veces por ejecución de su programa. Si estás fallando en un bucle cerrado (también conocido como golpearte la cabeza contra una pared de ladrillos), es probable que tu aplicación tenga peores problemas que ser lenta. Así que no se preocupe por el costo de lanzar una excepción a menos que de alguna manera se vea obligado a usarlos para controlar el flujo regular.

Alguien publicó una respuesta hablando de código de perfil que arroja una excepción. Nunca lo he probado yo mismo, pero con confianza predigo que esto mostrará un golpe de rendimiento mucho más grande que simplemente entrar y salir de un bloque de prueba sin lanzar nada.

Otra cosa a tener en cuenta es que donde anida llama a muchos niveles profundos, incluso puede ser más rápido para tener un solo intento...captura justo en la parte superior de lo que es para comprobar los valores de retorno y propagar errores en cada llamada.

En lo contrario de esa situación, donde encuentras que estás envolviendo cada llamada en su propio intento...bloqueo de captura, su código será más lento. Y más feo.

 63
Author: Steve Jessop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-20 15:21:05

Estaba aburrido y perfilé lo siguiente (dejé el código de tiempo fuera):

function no_except($a, $b) { 
    $a += $b;
    return $a;
}
function except($a, $b) { 
    try {
        $a += $b;
    } catch (Exception $e) {}
    return $a;
}

Usando dos bucles diferentes:

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) {}
}

Con 1000000 carreras en mi caja WinXP ejecute apache y 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

Estos resultados fueron consistentes y permanecieron en una proporción similar sin importar el orden en que se realizaron las pruebas.

Conclusión: Agregar código para manejar excepciones raras no es más lento que el código que ignora excepciones.

 49
Author: jmucchiello,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-21 09:27:49

Los bloques Try-catch no son un problema de rendimiento: el verdadero cuello de botella de rendimiento proviene de la creación de objetos de excepción.

Código de prueba:

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";
}

Resultados:

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,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-16 19:07:25

Generalmente, use una excepción para protegerse contra errores inesperados, y use la comprobación de errores en su código contra errores que forman parte del estado normal del programa. Para ilustrar:

  1. Registro no encontrado en el estado válido de la base de datos, debe verificar los resultados de la consulta y enviar mensajes al usuario de manera adecuada.

  2. Error SQL al intentar recuperar el registro-error inesperado, el registro puede o no estar allí, pero tiene un error de programa - este es un buen lugar para un error de registro de excepción en el registro de errores, envíe un correo electrónico al administrador con el seguimiento de la pila y muestre un mensaje de error cortés al usuario informándole de que algo salió mal y que está trabajando en ello.

Las excepciones son caras, pero a menos que maneje todo el flujo del programa usándolas, cualquier diferencia de rendimiento no debería ser perceptible por humanos.

 8
Author: Aeon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-19 18:51:20

No he encontrado nada en el rendimiento Try/Catch en Google, pero una prueba simple con un error de lanzamiento de bucle en lugar de una sentencia IF produce 329ms vs 6ms en un bucle de 5000.

 5
Author: Patrick Desjardins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-19 18:35:45

Lamento publicar un mensaje muy antiguo, pero he leído los comentarios y estoy un poco en desacuerdo, la diferencia podría ser mínima con una pieza simple de códigos, o podría ser negligente donde el Try / Catch se utilizan para partes específicas de código que no siempre son predecibles, pero también creo (no probado) que un simple:

if(isset($var) && is_array($var)){
    foreach($var as $k=>$v){
         $var[$k] = $v+1;
    }
}

Es más rápido que

try{
    foreach($var as $k=>$v){
        $var[$k] = $v+1;
    }
}catch(Exception($e)){
}

También creo (no probado) que a:

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

Es más caro que tener IFs adicionales en el código

 2
Author: Fabrizio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-08 16:29:07

¡Esa es una muy buena pregunta!

Lo he probado muchas veces y nunca vi ningún problema de rendimiento ;-) Era cierto hace 10 años en C++ pero creo que hoy lo han mejorado mucho ya que es tan útil y más limpio.

Pero todavía tengo miedo de rodear mi primer punto de entrada con él:

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

No he probado con un montón de funciones de llamada y gran incluir.... ¿Alguien ya lo ha probado completamente?

 1
Author: Tom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-03 11:43:34

En términos generales, son caros y no valen la pena en PHP.

Dado que es un lenguaje de expresiones marcado, debe capturar cualquier cosa que arroje una excepción.

Cuando se trata de código heredado que no arroja, y código nuevo que lo hace, solo conduce a la confusión.

¡Buena suerte!

 -8
Author: Ian P,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-19 18:31:57