Este artículo se compone de:
He estado investigando después de leer una noticia enviada por WebGranada que decía que los chicos de Facebook han hecho una herramienta que transforma el código de PHP a C++ y que al realizar las tareas con lenguaje de la máquina (bajo nivel),como es lógico ,es más rápido ,sin embargo, me preguntaba hasta que punto es más rápido…como no he visto nada serio que me convenza me he decidio por hacer mis propias pruebas con este tipo de construcción de webs a través de lenguaje C/C++ en lugar de PHP, e incluso escribir el código en PHP y pasarlo a C++…
De hecho, esto ya existía desde hace tiempo,…cualquiera puede implementar una herramienta como: The PHP to C++ Translation tool…que no es más que un programa en C++ que analiza sintácticamente un programa en PHP y lo pasa a C++ para que se pueda compilar y colgar en el servidor , por ejemplo la plataforma SWAD está escrita en este lenguaje y la especificación CGI…pero lo difícil es hacerlo bien, como casi siempre jeje
El debate que existe en Internet, ronda, en parte, a la cuestión de que no se va a conseguir una verdadera experiencia de mejora de velocidad en cuanto a interacción y carga de páginas, sobre todo en las que no tienes más de un número máximo, digamos, de más de miles de usuarios…ni tampoco, a la hora de conectarse a la base de datos ya que es algo que no suele mejorarse demasiado de una tecnología a otra ,no más de un 20%…
Sí que se notará cuando se realicen búsquedas y otras operaciones complejas con los datos ya que un programa en C++ está optimizado en memoria mucho más que PHP,siempre y cuando el programador haya llevado cuidado a la hora de escribir el código…además, al funcionar PHP como un módulo (extensión) del Servidor (por ejemplo Apache), tiene sus propios límites de memoria y ciclos de ejecución, darle los datos de entrada a un programa en C++ y que realice tareas complejas es más eficiente según qué casos…
Aquí propongo un ejemplo sencillo para demostrar en qué casos es mejor C++ que PHP, para empezar, si queremos ir probando todo lo que vamos haciendo, podemos crearnos un directorio en nuestro servidor llamado «c++», recordar añadirlo al .htaccess:
RewriteRule ^c\+\+(.*) – [PT]
…para que Apache no procese ese directorio con otra regla, (si le ponemos un password mejor)…ahora, un script sencillo para ejecutar programas como si estuviéramos en una consola:
shell.php:
<html> <head> <script type="text/javascript"> function loadXML(_cmd) { url="/c++/shell_exec.php"; if (window.XMLHttpRequest) { // codigo para IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); } else {// para IE6, IE5 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.open("GET",url+"?cmd="+_cmd,false); xmlhttp.send(null); document.getElementById('test').innerHTML= xmlhttp.responseText; if (document.frmT.b.checked) document.frmT.cmd.value=""; document.frmT.cmd.focus(); } </script> <title>Exec</title> </head> <body> <div id="test"> <h2>CONSOLA</h2> </div> <form name="frmT" onsubmit=" loadXML(document.frmT.cmd.value); return false;"> <input type="text" name="cmd" /> <input type="checkbox" name="b" value="1" id="b"/> <label for="b">Borrar</label> </form> <button type="button" onclick="loadXML(document.frmT.cmd.value); return false;">run</button> </body> </html>
Este código llamará, usando el truquito AJAX, al siguiente fichero PHP (ojo!: más peligroso):
shell_exec.php
$t = trim($_GET['cmd']); if (empty($t)) die("Escribe un comando chatin"); echo $_GET['cmd']."<br />"; echo str_replace("\n","<br />",passthru($_GET['cmd']));
Ahora podemos utilizarlo invocando directamente la URL:
Ya podemos probar nuestros programas en C++ subiéndolos y compilándolos online (si nuestro servidor tiene gcc), o bien, haciendo una llamada al programa compilado directamente por nosotros en local…Para los que son más de Windows, podéis instalar cygwin y descargar las librerías para hacer compilaciones de Linux: crosscompilers for cygwin (existe una versión para 64bits de las librerías), descomprimiéndolas en el directorio cygwin para poder llamar a g++-linux, por Ejemplo para compilar The PHP to C++ Translation tool:
$ g++-linux -o php2cpp php2cpp.cpp
No debe de darnos ningún error o advertencia…ahora podemos usar el comando desde el servidor para pasar un fichero en lenguaje php a un fichero en lenguaje C++ mediante:
./php2cpp entrada.php salida.cpp
de nuevo debemos compilar la salida para obtener un binario…
$g++-linux -o salida salida.cpp
Una vez que tenemos los binarios podemos usar la consola improvisada en el navegador, para dar permisos de ejecución a aquellos mediante
chmod 750 salida
Y entonces podemos cargar el programa desde el servidor como antes (una vez subido,claro)
./salida
Un ejemplo básico de C,sería una búsqueda binaria de datos,por ejemplo de triadas de vértices (x,y,z) de un conjunto de polígonos, dentro de un conjunto mayor,pero para no complicarnos, usaremos un array unidimensional, de valores dobles, un código como el siguiente nos vale:
#include <stdio .h> #include <time .h> #define tamanio 500 int busquedaBinaria(double *matrizOrdenada, int primero, int ultimo, double llave); int main () { clock_t t_antes,t_despues; double t,aux; int i,k; srandom(time(0)); for (k=1000; k< =3000; k+=1000){ t_antes = clock(); double *m = malloc (sizeof(double)*tamanio*k); for (i=0; i<tamanio*k; i++) { m[i] = (double) (rand()%1000)+1; } aux = busquedaBinaria(m,0,tamanio*k,m[(int) (tamanio*k)/2]); free(m); t_despues = clock(); t = (((double)(t_despues - t_antes)) / CLOCKS_PER_SEC); printf("<br><h1>%f</h1>segundos",t); } return 0; } /** * @brief function busquedaBinaria: * Busca desde matrizOrdenada[primero].. matrizOrdenada[ultimo] por llave. * @returns: indice del elemento encontrado, la llave, * en otro caso -(indice donde se puede insertar)-1. * @param int matrizOrdenada array de sorted (ascending) values. * @param int primero * @param int ultimo * @llave double llave * @return int */ int busquedaBinaria(double *matrizOrdenada, int primero, int ultimo, double llave) { while (primero < = ultimo) { // calcula el punto medio int mid = (primero + ultimo) / 2; if (llave > matrizOrdenada[mid]) // repite la busqueda si no esta en la mitad primero = mid + 1; else if (llave < matrizOrdenada[mid]) // repite la busqueda en la otra mitad ultimo = mid - 1; else // encuentra el item, lo devuelve return mid; } // no encontrado return -(primero + 1); }
Para compilar con gcc…
Ahora el mismo programa compilado con gcc, pero en PHP:
o2.php:
srand(null); $tamanio = 500; for ($k=1000; $k< =3000; $k+=1000){ $t_antes = microtime(true); $m = array(); for ($i=0; $i<$tamanio*$k; $i++) { $m[i] = doubleval(rand(1,1000)); } $aux = busquedaBinaria($m,0,$tamanio*$k, $m[($tamanio*$k)/2]); unset($m); $t_despues = microtime(true); $t = $t_despues - $t_antes; printf("<br><h1>%f</h1>segundos",$t); } /** * @brief function busquedaBinaria: * Busca desde matrizOrdenada[primero].. matrizOrdenada[ultimo] por llave. * @returns: indice del elemento encontrado, la llave, * en otro caso -(indice donde se puede insertar)-1. * @param int matrizOrdenada array de sorted (ascending) values. * @param int primero * @param int ultimo * @llave double llave * @return int */ function busquedaBinaria(&$matrizOrdenada, $primero, $ultimo, $llave) { while ($primero < = $ultimo) { $mid = ($primero + $ultimo) / 2; // calcula el punto medio if ($llave > $matrizOrdenada[$mid]) $primero = $mid + 1; // repite la busqueda si no esta en la mitad else if ($llave < $matrizOrdenada[$mid]) $ultimo = $mid - 1; // repite la busqueda en la otra mitad else return $mid; // encuentra el item, lo devuelve } return -($primero + 1); // no encontrado }
Resultados PHP:
He elegido las búsquedas ya que estas operaciones de ordenación, concatenación de cadenas, etc. son más rápidas que en PHP y se pueden ver en los resultados.
La gráfica muestra la diferencia de eficiencia entre C/C++ y PHP a la hora de ejecutar algoritmos complejos de búsqueda y ordenación…
Esta gráfica corresponde al benchmark entre C++ y PHP: tiempo usado, memoria usada ,código usado versus velocidad y tamaño comparando los programas más rápidos de PHP
Después de saber que C y C++ es mucho más rápido que PHP para manejar la memoria y realizar operaciones complejas como algoritmos de ordenación, podemos consultar algunas webs que han hecho análisis más profundos y sacan sus propias conclusiones al respecto:
Como conclusión personal, pienso en C siempre que necesite un algoritmo que consuma mucho tiempo o mucho espacio en memoria del servidor, por supuesto, este tipo de programas se usan en empresas para realizar diversas operaciones…si bien, no está mal recordar que si lo que necesitamos en un listado de productos con condiciones únicas podemos utilizar un algoritmo de C o C++ embebido en PL/SQL tal como dicta el manual de Oracle…
¿Casos reales? Por ejemplo, se podría implementar un algoritmo para una búsqueda en una red social como Badoo.com, si necesitamos encontrar todas las personas con los ojos azules, aplicarle a la primera foto de cada contacto un algoritmo, primero con el comando wget() (o con PHP) nos descargamos la imagen o un rango de ellas, a un directorio de caché, llamamos al programa en C++ (exec() ,CGI, o lo que sea) que analiza la/s foto/s y nos dá una probabilidad de que los ojos azules se encuentren en ella y basándose en estos datos, marcar el perfil de la persona pasado al script como apto para añadirlo a la lista de candidatos de nuestra base de datos…esto en PHP podría tardar pues…imaginaos jaja
Ni que decir tiene que el futuro nos depara webs en 3D programadas en C++ o las generaciones siguientes a este como LUA que transforma internamente el código a C++…y esto amigos, si que se nota comparado con un applet de Java :]
De hecho existen algoritmos que estudian su probabilidad de éxito en el marketing…no es nada descabellada la idea :)
Es la hora de comentarme o insultarme, lo que más os guste o lo que más rabia os de :D
Ah, te podemos insultar?
C…….. de ………
T….. l……. p….
y además….. pfoaksjdñlkrñokhasfd oink!!
Fdo:
El jaker del museo del prado.
LOL
hacker de óleos en acción!!
No me compila el archivo c++ me tira estos errores al compilarlos con gcc
c++.cpp: In function ‘int main()’:
c++.cpp:12: error: ‘srandom’ was not declared in this scope
c++.cpp:16: error: ‘malloc’ was not declared in this scope
c++.cpp:18: error: ‘rand’ was not declared in this scope
c++.cpp:22: error: ‘free’ was not declared in this scope
Hola Jorge, son problemas típicos de usar un lenguaje u otro, como ves yo he usado g++ de Linux para cygshell sobre Windows, tienes que utilizar la instrucción g++ y cambiar las lineas de referencias a librerías quitando los «.h» para que sea c++, añadiendo un include de la librería cstdlib.
En cualquier caso, este problema es muy típico en C y una búsqueda en internet te hubiera solucionado la duda en un periquete jeje
Un saludo
jejeje!!
#include <stdlib.h>
Hola muy interesante el ejemplo, cuando lo ejecuto directo en la consola funciona perfecto, sin embargo, en el navegador me muestra el mismo texto que le paso al textfield y no me muestra los segundos de ejecución.
Gracias de antemano.
tendrás que comprobar si tu servidor tiene permisos de ejecución de comandos comprometidos como exec( ) o passthru( ), esto suele estar en la información que devuelve la función phpmyinfo(); y tiene que ver con el parámetro de configuración safe_mode (y safe_mode_exec_dir) que como verás, está obsoleta a partir de versiones 5.3.0 …
Mira esos parámetros, puedes intentar probar el script en local mientras …un saludo
La verdad, te felicito por este analisis. Me ahorraste mucho tiempo, pues siempre es bueno comprobar las cosas por uno mismo… Me repito … muy buen aporte a la comunidad
Gracias Sr Puentes
Buen articulo,
El C++, tiene dos parametros en el main (int argc, char *argv[]), y en java tambien tiene pero es solo un parametro sino me equivoco, bueno la idea es que seria mas buena la interaccion con esos parametros y procesarlos en el C++, y en el PHP solo lo ejecutamos o le enviamos los parametros.
Saludos
Gildus
Hola Gildus, en Java depende de como lances el programa, si es un applet o un webservice los parámetros serían como en PHP ya que es el navegador quien hospeda la máquina virtual, en el caso de lanzarlo como línea de comandos con java o el compilador tienes el mismo caso que en C.
No cambia mucho el tiempo de los ejemplos ya que el procesado de dichos parámetros es trivial…es decir, tendrías que cambiar algo más para poder medirlo, te invito a realizar las pruebas y compartirlas ;-)
Saludos, qué se puede hacer en el caso de base de datos y JSON y hacer un listener http, osea en vez de ejecutar con exec dejarlo en un listener http:8080
Q opinan?
Daniel, si creas un servidor de sockets en el puerto 8080 y quieres lanzarlo ,en lugar de un exec usa una tarea cron,al ser un programa en c++ será más rápido que con uno en PHP, luego ya depende de lo que hagas en ese programa…
por si alguien prueba y le sale error en esta parte:
double *m = malloc sizeof(double)*tamanio*k);
su corrección:
double *m = (double*) malloc(sizeof(double)*tamanio*k);