Optimización del rendimiento de aplicaciones PHP.
El mayor beneficio de programar en PHP es lo fácil que es aprender este lenguaje de programación y sus ricas bibliotecas. Incluso si no sabemos mucho sobre las funciones que necesitamos usar, podemos adivinar cómo realizar una tarea específica.
Aunque PHP es muy simple y fácil de aprender, todavía necesitamos dedicar un poco de tiempo a aprender algunas habilidades de programación de PHP, especialmente aquellas relacionadas con el rendimiento y el uso de la memoria. En PHP existen muchos trucos que nos permiten reducir el uso de memoria y mejorar el rendimiento de las aplicaciones. En este artículo, presentaremos brevemente el análisis de aplicaciones PHP, cómo cambiar el código del script y compararemos varios valores de parámetros antes y después de la optimización.
Al configurar procedimientos de sincronización en el programa y ejecutar estos códigos repetidamente, podemos obtener un conjunto de datos sobre la velocidad de ejecución del programa. Estos datos se pueden utilizar para descubrir cuellos de botella en el programa y cómo optimizarlo para mejorar el rendimiento del mismo. solicitud.
Quizás los lectores hayan oído hablar de la biblioteca PEAR. Usaremos la biblioteca PEAR para crear ejemplos que necesitamos usar durante el análisis. Esta es también la forma más fácil de analizar el código existente. Nos permite analizar el código sin utilizar productos comerciales.
El nombre de la biblioteca que vamos a utilizar es PEAR::Benchmark y es muy útil para perfilar y probar el rendimiento del código. Esta biblioteca proporciona una clase llamada Benchmark_Timer(), que puede registrar el tiempo entre una llamada a función y la siguiente llamada a función. Al probar el rendimiento del código, podemos obtener un resultado detallado de la ejecución del script, que es muy simple, de la siguiente manera:
include_once("Benchmark/Timer.php");
$banco = nuevo Benchmark_Timer;
$banco->inicio();
$bench-> setMarker('Inicio del script');
// Ahora en estado de suspensión durante unos minutos.
dormir(5);
$banco->parar();
// Obtener información de análisis del temporizador
print_r($bench->getProfiling());
?>
El resultado después de ejecutar el código anterior es el siguiente:
Formación
(
[0] => Matriz
(
[nombre] => Inicio
[hora] => 1013214253.05751200
[diferencia] => -
[total] => 0
)
[1] => Matriz
(
[nombre] => Inicio del script
[hora] => 1013214253.05761100
[diferencia] => 9.8943710327148E-05
[total] => 9.8943710327148E-05
)
[2] => Matriz
(
[nombre] => Detener
[hora] => 1013214258.04920700
[diferencia] => 4.9915959835052
[total] => 4,9916949272156
)
)
Los números anteriores pueden parecer un conjunto inconexo de números, pero si el tamaño del programa es mayor, estos números pueden resultar muy útiles.
Quizás la mayoría de los lectores también puedan adivinar que la primera entrada en la matriz es el método real para llamar a la clase Benchmark_Timer(), por ejemplo.
$bench->start(), $bench->setMarker() y $bench->stop() Los números asociados con estas entradas son bastante simples. Ahora echemos un vistazo más de cerca a estos números.
[0] => Matriz
(
[nombre] => Inicio
[hora] => 1013214253.05751200
[diferencia] => -
[total] => 0
)
La entrada de tiempo se refiere a la marca de tiempo de UNIX cuando se llama al método start() de Benchmark_Timer(). La entrada diff indica el intervalo de tiempo entre esta llamada y la última llamada. Dado que aquí no hay una llamada previa, un guión, la entrada total. se refiere al tiempo total que el código ha estado ejecutándose desde el inicio de la prueba hasta esta llamada en particular. Echemos un vistazo al resultado de la siguiente matriz:
[1] => Matriz
(
[nombre] => Inicio del script
[hora] => 1013214253.05761100
[diferencia] => 9.8943710327148E-05
[total] => 9.8943710327148E-05
)
De los números anteriores podemos ver que después de llamar a $bench->start(), el programa se ejecuta durante 9.8943710327148E-05 segundos (es decir, 0.0000989 segundos) antes de llamar a $bench->setMarker(….).
Una experiencia real de prueba de rendimiento
Si bien el ejemplo anterior es bueno, en realidad no es un buen ejemplo para decidir cómo optimizar el diseño del código de su sitio. A continuación, utilizaré mi propia experiencia personal como técnico de sitios web para ilustrar cómo resolver problemas de rendimiento.
Realmente no entiendo el código utilizado por el sitio web, porque se desarrolló durante muchos años en función de necesidades específicas: un módulo contiene el código de conversión del sitio web, otro módulo registra el uso del sitio web y los otros módulos tienen el suyo propio. papel de cada uno. El desarrollador principal del sitio web y yo nos dimos cuenta de que era necesario optimizar el código del sitio web, pero no sabíamos cuál era el problema.
Para completar la tarea lo más rápido posible, comencé a estudiar el código de script principal del sitio web y agregué algunos comandos $bench->setMarker() a todos los códigos de script y sus archivos incluidos, luego analicé el resultado de $bench. ->getProfiling(), y me sorprendieron los resultados. Resultó que el problema radicaba en una llamada de función relacionada con el código de conversión para obtener un nombre de idioma específico (como en para inglés), que se usó cientos de veces. en cada página. Cada vez que se llama a esta función, el código del script consulta una base de datos MySQL para obtener el nombre real del idioma de una tabla de base de datos.
Entonces creamos un sistema de almacenamiento en búfer para este tipo de información. Después de solo 2 días de trabajo, mejoramos enormemente el rendimiento del sistema y la cantidad de páginas vistas aumentó en un 40% en la primera semana. Por supuesto, este es sólo un ejemplo de cómo el análisis de código puede mejorar el rendimiento de una aplicación de Internet o un sitio web de Internet.
Llamada a la función de prueba de rendimiento
Aunque Benchmark_Timer() es particularmente útil al analizar un script o una página web (y los archivos que lo contienen), no es científico porque debemos cargar el script varias veces para obtener los datos analizados y no es específico de una determinada clase o función. . llamado.
Otra clase en la biblioteca PEAR::Benchmark llamada Benchmark_Iterator puede resolver este problema muy bien. Puede mostrar información de análisis para una función o método de clase específico. Su propósito es poder obtener resultados consistentes de las pruebas porque sabemos que si ejecutamos un script una vez y tarda 10 segundos en ejecutarse, eso no significa que siempre tomará 10 segundos en ejecutarse cada vez.
En cualquier caso, veamos algunos ejemplos:
// Código para conectarse a la base de datos
include_once("DB.php");
$dsn = matriz(
'phptipo' => 'mysql',
'hostspec' => 'localhost',
'base de datos' => 'nombre_base_datos',
'nombre de usuario' => 'nombre_usuario',
'contraseña' => 'contraseña'
);
$dbh = DB::conectar($dsn);
función obtenerFechaCreada($id)
{
global $dap;
> $stmt = "SELECCIONE fecha_creación DE los usuarios DONDE id=$id";
// Usa PEAR::DB aquí
$created_date = $dbh-> getOne($stmt);
if ((PEAR::isError($created_date)) ||
(vacío($created_date))) {
devolver falso;
} demás {
devolver $fecha_creada;
}
}
include_once 'Benchmark/Iterate.php';
$banco = nuevo Benchmark_Iterate;
//Ejecutamos la función getDate 10 veces
$bench-> run(10, 'getCreatedDate', 1);
//Imprimir información de análisis
print_r($banco->get());
?>
La ejecución del código anterior produce resultados similares a los siguientes:
Formación
(
[1] => 0,055413007736206
[2] => 0,0012860298156738
[3] => 0,0010279417037964
[4] => 0,00093603134155273
[5] => 0,00094103813171387
[6] => 0,00092899799346924
[7] => 0,0010659694671631
[8] => 0,00096404552459717
[9] => 0,0010690689086914
[10] => 0,00093603134155273
[media] => 0,0064568161964417
[iteraciones] => 10
)
Los números anteriores son fáciles de entender. La entrada media representa el tiempo promedio de 10 ejecuciones de la función getCreatedDate(). En las pruebas reales, debes ejecutarlo al menos 1000 veces, pero los resultados de este ejemplo son suficientes para ilustrar el problema.