2010-01-20 12 views
7

¿Qué patrón de diseño existe para realizar la ejecución de algunos procesos PHP y la recopilación de los resultados en un proceso PHP?Patrones para procesos múltiples PHP?

Antecedentes:
tengo muchos árboles grandes (> 10000 entradas) en PHP y tienen que ejecutar comprobaciones recursivas en él. Quiero reducir el tiempo de ejecución transcurrido.

+4

... escribir una extensión C? – jldupont

Respuesta

7

Si su objetivo es el tiempo mínimo, la solución es simple de describir, pero no tan simple de implementar.

Necesita encontrar un patrón para dividir el trabajo (No proporciona mucha información en la pregunta al respecto).

A continuación, utilice un proceso maestro que forks niños para hacer el trabajo. Como regla general, la cantidad total de procesos que utiliza debe estar entre n y 2n, donde n es la cantidad de núcleos que tiene la máquina.

Suponiendo que estos datos se almacenen en archivos, puede considerar el uso de E/S sin bloqueo para maximizar el rendimiento. Si no lo hace, la mayor parte de su proceso pasará un tiempo esperando el disco. PHP tiene stream_select() que podría ayudarte. Tenga en cuenta que usarlo no es trivial.

Si decide no usar select, aumentar el número de procesos puede ayudar.


En lo que respecta a pcntl funciones: He escrito un demonio con ellos (una apropiada con la bifurcación, el cambio de ID de sesión, el usuario que ejecuta, etc ...) y es una de las piezas más fiable de software que he escrito Debido a que genera trabajadores para cada tarea, incluso si hay un error en una de las tareas, no afecta a los demás.

+0

¡Bien hecho, la información de stream_select()! – powtac

+0

Para ver stream_select en acción, verifique el código en http://drupal.org/project/httprl. Planeo empujar esta biblioteca a Github una vez que la haya pulido más; algo que se puede ejecutar fuera de drupal. Puede usar esto como un ejemplo de cómo complejo stream_select puede obtener. – mikeytown2

10

Desde su script php, podría iniciar otro script (usando exec) para hacer el procesamiento. Guarde las actualizaciones de estado en un archivo de texto, que luego podría leer periódicamente el hilo principal.

Nota: para evitar php esperando el guión exec 'd para completar, canalizar la salida a un archivo:

exec('/path/to/file.php | output.log'); 

Alternativamente, puede bifurcar un guión usando las funciones PCNTL. Utiliza una secuencia de comandos php, que cuando se abre puede detectar si es el padre o el hijo y funciona en consecuencia. Hay funciones para enviar/recibir señales con el propósito de comunicarse entre padres/hijos, o tiene el registro hijo en un archivo y el padre lee de ese archivo.

Desde la página de manual de pcntl_fork:

$pid = pcntl_fork(); 
if ($pid == -1) { 
    die('could not fork'); 
} else if ($pid) { 
    // we are the parent 
    pcntl_wait($status); //Protect against Zombie children 
} else { 
    // we are the child 
} 
+0

"Escuché" que pcntl no es una buena solución. Alguna experiencia? – powtac

+1

Lo sentimos, realmente no tenemos ninguna experiencia práctica de eso. Buscando a través de SO, me sorprende cuánta gente dice categóricamente que no hay forma de forking php –

+2

He escrito un envoltorio Perl antes de usar FORK (en Perl) para ejecutar un script PHP con excelentes resultados. –

4

Esto podría ser un buen momento para considerar el uso de un message queue, incluso si se ejecuta en una sola máquina.

+0

El problema con una cola de mensajes es que necesitamos el mismo espacio de nombres/alcance global para los diferentes procesos. – powtac

+1

No estoy seguro de lo que necesita para el ámbito compartido y el espacio de nombres, pero una cola de mensajes, junto con la memoria compartida (por ejemplo, Memcache) podría ser una posibilidad. – sfrench

+0

La solución Message Que se adapta mejor a esta gran aplicación a escala. Con Memcache podemos controlar muy bien qué hacer cuando. Como todo es muy OO, no hay un gran problema con el espacio de nombres. Tengo que llenar los objetos desde y hacia Memcache. – powtac

1

¿Se usa web o CLI?

Si usa web, podría integrar esa parte en Quercus Entonces podría usar las ventajas de multiprocesar JAVA.

En realidad, no sé cuán confiable es Quercus. También sugiero usar un tipo de cola de mensajes y refactorizar el código, por lo que no necesita el alcance.

Tal vez podría reconstruir el código en un patrón de Mapa/Reducir. Luego puede ejecutar el código PHP en Hadoop. Luego puede agrupar el procesamiento a través de un par de máquinas.

No sé si es útil, pero me encontré con otro proyecto, llamado Gearman. También se usa para agrupar procesos PHP. Supongo que también puedes combinar eso con una secuencia de comandos reducida, si Hadoop no es la forma en que quieres ir.

+0

No quiero usar una implementación Java de PHP, parece un poco "hinchada". – powtac

+0

Probé Quercus, no está mal pero no es 100% compatible con el código existente. Probablemente, usar un clúster Hadoop es la solución más rápida. – rtacconi

+0

¡El mapa/reducción es una muy buena pista! – powtac

2

La pregunta parece un poco confusa.

Quiero reducir el tiempo de ejecución absoluto.

¿Se refiere a elapsed time? Ciertamente, el uso de la estructura de datos correcta mejorará el rendimiento, pero para una estructura de datos dada, el orden mínimo del algoritmo es absoluto, y nada que ver con la forma en que se implementa el algoritmo.

¿Qué patrón de diseño existe para darse cuenta ...?

patrones de diseño son algo que codifican es, no una plantilla para escribir programas, y unas herramientas útiles para el diseño curricular. Para comenzar con un patrón y hacer que su código encaje, es en sí mismo un antipatrón.

Nadie puede responder esta pregunta sin saber mucho más sobre sus datos y cómo está estructurado, sin embargo, el factor clave para la eficiencia será la estructura de datos que utilice para implementar su árbol. Si el tiempo transcurrido es importante, entonces observe la ejecución paralela, sin embargo, también puede valer la pena considerar realizar la operación en una herramienta diferente: las bases de datos están altamente optimizadas para manejar grandes conjuntos de datos, pero tenga en cuenta que el método obvio para describir un árbol una base de datos relacional es muy ineficiente cuando se trata de aislar subárboles y caminar por el árbol.

En respuesta a Adán lo que sugiere que se bifurcan de que respondió:

I "oído" que PCNTL tampoco una buena solución. Alguna experiencia?

¿Dónde oíste eso? Ciertamente, bifurcar desde un script CGI o mod_php invocado es una mala idea, pero no hay nada de malo en hacerlo desde la línea de comando. Tenga un google para procesos PHP de larga ejecución (tenga en cuenta que hay mucha información mala por ahí). El código que escriba variará según el sistema operativo subyacente, que no ha indicado.

Sospecho que podría resolver una gran parte de sus problemas de rendimiento identificando qué partes del árbol necesitan verificarse y solo revisando esas partes Y activando las comprobaciones cuando se actualiza el árbol, o al menos marcando los nodos como 'sucio'.

Usted puede encontrar estos útiles:

http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/ http://en.wikipedia.org/wiki/Threaded_binary_tree

C.

3

Se podría utilizar una estructura de datos más eficiente, como un árbol b. Utilicé una vez en Java pero no en PHP.Puede probar este script: http://www.phpclasses.org/browse/file/708.html, es una implementación de btree.

Si no es suficiente, puede usar Hadoop para implementar un patrón de Mapa/Reducir, como dijo Michael. No me inclinaría por el proceso de PHP, no parece ayudar para el rendimiento.

Personalmente, utilizaría PHP como cliente y pondría todo en Hadoop. Este tutorial puede ayudar: http://www.lunchpauze.com/2007/10/writing-hadoop-mapreduce-program-in-php.html.

Otra solución puede ser utilizar una implementación de Java de Btree: http://jdbm.sourceforge.net/. JDBM es una base de datos de objetos que utiliza una estructura de datos Btree +. A continuación, puede buscar con PHP mediante la exposición de datos con un servicio web o accediendo directamente con Quercus

+0

¡Hadoop es una buena recomendación! – powtac

0

pthreads

Hay una extensión bastante nuevo (desde 2012) PHP disponibles: pthreads. Se puede instalar a través del PECL.

Implementación simple en código PHP: extender desde Thread Clase. Agregue un método run() y ejecute el método start().

<?php 
// Example from http://www.phpgangsta.de/richtige-threads-in-php-einfach-erstellen-mit-pthreads 
class AsyncOperation extends Thread 
{ 
    public function __construct($threadId) 
    { 
     $this->threadId = $threadId; 
    } 

    public function run() 
    { 
     printf("T %s: Sleeping 3sec\n", $this->threadId); 
     sleep(3); 
     printf("T %s: Hello World\n", $this->threadId); 
    } 
} 

$start = microtime(true); 
for ($i = 1; $i <= 5; $i++) { 
    $t[$i] = new AsyncOperation($i); 
    $t[$i]->start(); 
} 
echo microtime(true) - $start . "\n"; 
echo "end\n"; 

salidas

>php pthreads.php 
0.041301012039185 
end 
T 1: Sleeping 3sec 
T 2: Sleeping 3sec 
T 3: Sleeping 3sec 
T 4: Sleeping 3sec 
T 5: Sleeping 3sec 
T 1: Hello World 
T 2: Hello World 
T 3: Hello World 
T 4: Hello World 
T 5: Hello World 
Cuestiones relacionadas