2008-09-19 12 views
49

¿Qué tipo de implicaciones de rendimiento hay que tener en cuenta al usar las declaraciones try-catch en php 5?Rendimiento de try-catch en php

He leído información anterior y aparentemente contradictoria sobre este tema en la web anteriormente. Mucho 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.

Respuesta

60

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

Si las excepciones solo se producen en casos de error, es casi seguro que no le importa el rendimiento, ya que no fallará muchas veces por cada ejecución de su programa. Si está fallando en un círculo cerrado (por ejemplo: golpearse la cabeza contra una pared de ladrillos), es probable que su aplicación tenga problemas peores que la lentitud. Por lo tanto, no se preocupe por el costo de lanzar una excepción a menos que de algún modo se vea obligado a usarlos para un flujo de control regular.

Alguien ha publicado una respuesta sobre el código de creación de perfiles que arroja una excepción. Nunca lo probé yo mismo, pero predigo confiadamente que esto mostrará un golpe de rendimiento mucho mayor que solo entrar y salir de un bloque de prueba sin tirar nada.

Otra cosa a tener en cuenta es que cuando anida llamadas a muchos niveles de profundidad, incluso puede ser más rápido tener una sola oportunidad ... atrapar en la parte superior de lo que es verificar los valores de retorno y propagar errores en cada llamada.

En la situación opuesta a la situación en la que te encuentras envolver cada llamada en su propio intento ... atrapar bloque, tu código será más lento. Y más feo

+0

¡Nunca he visto el código donde envuelven cada llamada con un 'try catch' en lugar de usar una sola gran' try cacth' para envolver todas las llamadas! –

+2

@Marco: ocurre en código que no * quiere * usar excepciones en sí mismo, pero se ve obligado a usar una API que sí lo haga. Así que cada llamada a esa API termina envuelta, atrapando excepciones y convirtiéndolas en códigos de error o lo que sea. Tal vez eso no surja realmente en PHP, pero puede ser un peligro en otros lenguajes cuando chocan diferentes estilos de codificación. La otra ocasión es cuando desea manejar las excepciones de manera muy diferente según su procedencia (registrando silenciosamente algunas, advirtiendo al usuario acerca de otras, fallando en otras) en lugar de solo el tipo de excepción. Entonces necesitas muchos try-catch. –

-8

En general, son caros y no valen la pena en PHP.

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

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

¡Buena suerte!

+2

Para el registro, PHP no tiene "controlada excepciones". Todas las excepciones funcionan como "RuntimeException" de Java. – RJHunter

5

no he encontrado nada en el rendimiento try/catch en Google pero una prueba simple con un bucle de error de tiro en lugar de una sentencia if producen 329ms vs 6 ms en un bucle de 5000.

+7

¿Te importa publicar el código que usaste para que se pueda verificar? – UnkwnTech

+2

También me gustaría ver el código que usaste para esto si aún lo tienes :-) –

+0

@Patrick Desjardins: podrías publicar el código para tu prueba o darnos un enlace. –

8

general, el uso de una excepción protegerse contra fallas inesperadas y utilizar la comprobación de errores en su código contra fallas que son parte del estado normal del programa. Para ilustrar:

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

  2. Error de SQL al intentar recuperar el registro - error inesperado, el registro puede estar o no, pero tiene un error de programa - este es un buen lugar para una excepción - error de registro en el registro de errores, envíele un correo electrónico al administrador apila la traza y muestra un mensaje de error educado al usuario indicándole que algo salió mal y que estás trabajando en ello.

Las excepciones son costosas, pero a menos que maneje todo el flujo de programa utilizándolas, cualquier diferencia de rendimiento no debe ser perceptible por el ser humano.

45

estaba aburrido y perfilado los siguientes (Salí del código de tiempo de espera):

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 se ejecuta en mi WinXP Apache cuadro de ejecución 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 se mantuvieron en una proporción similar sin importar w qué orden ejecutaron las pruebas.

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

+0

la función 'except' no arroja una excepción. ¿Esta era tu prueba intencionada? –

+8

No, la intención era perfilar el código que "puede" manejar excepciones. No hacer un perfil del mecanismo real de lanzamiento/captura. Los datos demuestran que simplemente poner los bloques try/catch en su código no agrega una sobrecarga significativa. – jmucchiello

+0

gracias por aclarar que :-) –

1

¡Esa es una muy buena pregunta!

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

Pero estoy teniendo miedo a rodear mi primer punto de entrada con ella:

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

yo ni prueba con un montón de funciones llaman y grande incluyen .... ¿Alguien ha probar completamente ya?

2

Perdón por publicar un mensaje muy antiguo, pero leí los comentarios y no estoy de acuerdo, la diferencia podría ser mínima con un simple fragmento de código, o podría ser negligente que Try/Catch se use 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:

<?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 tienen los fondos de inversión adicionales en el código

+2

La pregunta era si el método "más caro" (prueba/captura) puede degradar el rendimiento o si el impacto es mínimo. – StefanNch

14

bloques try-catch no son un problema de rendimiento - el cuello de botella real viene de la creación de objetos de excepción.

Código de ensayo:

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 
+0

Reproduje estos resultados usando PHP 5.4.22 con un valor 'memory_limit' de 128 MB. +1 Bonito script de banqueo –

Cuestiones relacionadas