¿PHP tiene threading?


Encontré este paquete PECL llamado threads, pero todavía no hay una versión. Y nada está apareciendo en el sitio web de PHP.

Author: Josh K, 2008-10-16

13 answers

No Hay nada disponible, que yo sepa. Lo mejor sería simplemente hacer que un script ejecute otro a través de CLI, pero eso es un poco rudimentario. Dependiendo de lo que usted está tratando de hacer y lo complejo que es, esto puede o no puede ser una opción.

 40
Author: Wilco,
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-10-16 18:55:23

Del manual de PHP para la pthreads extensión:

Pthreads es una API orientada a Objetos que permite el multi-threading en PHP. Incluye todas las herramientas que necesita para crear aplicaciones multihilo dirigidas a la Web o la consola. Las aplicaciones PHP pueden crear, leer, escribir, ejecutar y sincronizar con Hilos, Trabajadores y Apilables.

Por increíble que suene, es totalmente cierto. Hoy en día, PHP puede multi-thread para aquellos deseando probarlo.

La primera versión de PHP4, 22 de mayo de 2000, PHP fue enviado con una arquitectura segura de subprocesos - una forma para que ejecute múltiples instancias de su intérprete en subprocesos separados en entornos SAPI ( Server API ) multi-threaded. Durante los últimos 13 años, el diseño de esta arquitectura se ha mantenido y avanzado: ha estado en uso de producción en los sitios web más grandes del mundo desde entonces.

El threading en la tierra del usuario nunca fue una preocupación para el equipo de PHP, y permanece como tal hoy. Debe entender que en el mundo donde PHP hace su negocio, ya hay un método definido de escalado: agregar hardware. A lo largo de los muchos años que PHP ha existido, el hardware se ha vuelto más y más barato, por lo que esto se convirtió en una preocupación cada vez menor para el equipo de PHP. Si bien era cada vez más barato, también se hizo mucho más potente; hoy en día, nuestros teléfonos móviles y tabletas tienen arquitecturas de doble y cuádruple núcleo y mucha RAM para ir con él, nuestros escritorios y servidores comúnmente tener 8 o 16 núcleos, 16 y 32 gigabytes de RAM, aunque no siempre podemos tener dos dentro del presupuesto y tener dos escritorios rara vez es útil para la mayoría de nosotros.

Además, PHP fue escrito para el no programador, es la lengua nativa de muchos aficionados. La razón por la que PHP es tan fácil de adoptar es porque es un lenguaje fácil de aprender y escribir. La razón por la que PHP es tan confiable hoy en día es debido a la gran cantidad de trabajo que se dedica a su diseño, y cada decisión tomada por el Grupo PHP. Su fiabilidad y pura grandeza lo mantienen en el punto de luz, después de todos estos años; donde sus rivales han caído al tiempo o la presión.

La programación multihilo no es fácil para la mayoría, incluso con la API más coherente y confiable, hay diferentes cosas en las que pensar y muchos conceptos erróneos. El grupo PHP no desea que el multi-threading de tierra de usuario sea una característica principal, nunca se le ha prestado atención seria , y con razón. PHP no debe ser complejo, para cada.

Considerando todas las cosas, todavía hay beneficios de permitir que PHP utilice sus características listas para producción y probadas para permitir un medio de aprovechar al máximo lo que tenemos, cuando agregar más no siempre es una opción, y para muchas tareas nunca es realmente necesario.

Pthreads logra, para aquellos que deseen explorarlo, una API que permite a un usuario múltiples subprocesos de aplicaciones PHP. Su API es en gran medida un trabajo en progreso, y designado un nivel beta de estabilidad e integridad.

Es de conocimiento común que algunas de las bibliotecas que usa PHP no son seguras para subprocesos, debe estar claro para el programador que pthreads no puede cambiar esto, y no intenta intentarlo. Sin embargo, cualquier biblioteca que sea segura para subprocesos es utilizable, como en cualquier otra configuración segura para subprocesos del intérprete.

Pthreads utiliza hilos Posix (incluso en Windows), lo que el programador crea son hilos de ejecución reales, pero para que esos hilos sean útiles, deben ser consciente de PHP-capaz de ejecutar código de usuario, compartir variables y permitir un medio útil de comunicación ( sincronización ). Por lo tanto, cada subproceso se crea con una instancia del intérprete, pero por diseño, su intérprete está aislado de todas las demás instancias del intérprete, al igual que los entornos API de servidor multiproceso. pthreads intenta cerrar la brecha de una manera sana y segura. Muchas de las preocupaciones del programador de hilos en C simplemente no están allí para el programador de pthreads, por el diseño, pthreads es copiar al leer y copiar al escribir (la RAM es barata ), por lo que no hay dos instancias que manipulen los mismos datos físicos, pero ambas pueden afectar los datos en otro subproceso. El hecho de que PHP pueda usar características inseguras de subprocesos en su programación principal es completamente irrelevante, los subprocesos de usuario y sus operaciones son completamente seguras.

Por qué copiar en leer y copiar en escribir:

public function run() {
    ...
    (1) $this->data = $data;
    ...
    (2) $this->other = someOperation($this->data);
    ...
}

(3) echo preg_match($pattern, $replace, $thread->data);

(1) Mientras se mantiene un bloqueo de lectura y escritura en el almacén de datos de objetos pthreads, los datos se copian desde su ubicación original en memoria hasta el almacén de objetos. pthreads no ajusta el refcount de la variable, Zend puede liberar los datos originales si no hay más referencias a ellos.

(2) El argumento a someOperation hace referencia al almacén de objetos, los datos originales almacenados, que a su vez una copia del resultado de (1), se copia de nuevo para el motor en un contenedor zval, mientras que esto ocurre un bloqueo de lectura se mantiene en el almacén de objetos, el bloqueo se libera y ejecutar la función. Cuando se crea el zval, tiene un refcount de 0, lo que permite al motor liberar la copia al finalizar la operación, porque no existen otras referencias a ella.

(3) El último argumento a preg_match hace referencia al almacén de datos, se obtiene un bloqueo de lectura, el conjunto de datos en (1) se copia a un zval, de nuevo con un refcount de 0. El bloqueo se libera, la llamada a preg_match opera en una copia de datos, que es en sí misma una copia de los datos originales.

Cosas para saber:

  • La tabla hash del almacén de objetos donde se almacenan los datos, thread safe, es
    basado en la TsHashTable enviada con PHP, por Zend.

  • El almacén de objetos tiene un bloqueo de lectura y escritura, un bloqueo de acceso adicional se proporciona para la TsHashTable tal que si requiere ( y lo hace, var_dump/print_r, acceso directo a las propiedades como el motor PHP quiere hacer referencia a ellos ) pthreads puede manipular la TsHashTable fuera de la API.

  • Las cerraduras solo se mantienen mientras se realizan las operaciones de copia, cuando se han hecho las copias, las cerraduras se liberan, en un orden razonable.

Esto significa:

  • Cuando se produce una escritura, no solo se mantiene un bloqueo de lectura y escritura, sino bloqueo de acceso adicional. La mesa en sí está cerrada, no hay posible forma en que otro contexto puede bloquearlo, leerlo, escribirlo o afectarlo.

  • Cuando se produce una lectura, no solo es la lectura bloqueo sostenido, pero el bloqueo de acceso adicional también, de nuevo la mesa está bloqueada.

No hay dos contextos que puedan acceder física o simultáneamente a los mismos datos del almacén de objetos, pero las escrituras realizadas en cualquier contexto con una referencia afectarán a los datos leídos en cualquier contexto con una referencia.

Esto es arquitectura nada compartida y la única manera de existir es coexistir. Aquellos un poco inteligentes verán que, hay un montón de copias pasando aquí, y se preguntarán si eso es una buena cosa. Una gran cantidad de copias se realiza dentro de un tiempo de ejecución dinámico, esa es la dinámica de un lenguaje dinámico. pthreads se implementa a nivel del objeto, porque se puede obtener un buen control sobre un objeto, pero los métodos - el código que ejecuta el programador - tienen otro contexto, libre de bloqueo y copias-el ámbito del método local. El ámbito del objeto en el caso de un objeto pthreads debe tratarse como una forma de compartir datos entre contextos, ese es su propósito. Con esto en mente, puede adoptar técnicas para evitar bloquear el almacén de objetos a menos que sea necesario, como pasar variables de ámbito local a otros métodos en un objeto enhebrado en lugar de hacer que se copien desde el almacén de objetos al ejecutarse.

La mayoría de las bibliotecas y extensiones disponibles para PHP son envoltorios finos alrededor de 3 partes, la funcionalidad del núcleo de PHP hasta cierto punto es la misma cosa. pthreads no es una envoltura delgada alrededor de hilos Posix; es una API de subprocesos basada en hilos Posix. No tiene sentido implementando hilos en PHP que sus usuarios no entienden o no pueden usar. No hay razón para que una persona sin conocimiento de lo que es o hace un mutex no pueda aprovechar todo lo que tiene, tanto en términos de habilidades como de recursos. Un objeto funciona como un objeto, pero donde dos contextos chocarían, pthreads proporciona estabilidad y seguridad.

Cualquiera que haya trabajado en java verá las similitudes entre un objeto pthreads y threading en java, esas mismas personas sin duda habrán visto un error llamado ConcurrentModificationException, ya que suena un error generado por el tiempo de ejecución de Java si dos subprocesos escriben los mismos datos físicos simultáneamente. Entiendo por qué existe, pero me desconcierta que con recursos tan baratos como son, junto con el hecho de que el tiempo de ejecución es capaz de detectar la concurrencia en el momento exacto y único en que se podría lograr la seguridad para el usuario, que elige lanzar un error posiblemente fatal en tiempo de ejecución en lugar de gestionar la ejecución y el acceso a los datos.

No se emitirán tales errores estúpidos por pthreads, la API está escrita para hacer que el threading sea lo más estable y compatible posible, creo.

Multi-threading no es como usar una nueva base de datos, se debe prestar mucha atención a cada palabra en el manual y los ejemplos enviados con pthreads.

Por último, del manual de PHP:

Pthreads fue, y es, un experimento con resultados bastante buenos. Cualquiera de sus limitaciones o las características pueden cambiar en cualquier momento; esa es la naturaleza de la experimentación. Sus limitaciones-a menudo impuestas por la implementación-existen por una buena razón; el objetivo de pthreads es proporcionar una solución utilizable a la multitarea en PHP a cualquier nivel. En el entorno que pthreads ejecuta, algunas restricciones y limitaciones son necesarias para proporcionar un entorno estable.

 172
Author: Joe Watkins,
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-01-28 11:44:57

Aquí hay un ejemplo de lo que Wilco sugirió:

$cmd = 'nohup nice -n 10 /usr/bin/php -c /path/to/php.ini -f /path/to/php/file.php action=generate var1_id=23 var2_id=35 gen_id=535 > /path/to/log/file.log & echo $!';
$pid = shell_exec($cmd);

Básicamente esto ejecuta el script PHP en la línea de comandos, pero inmediatamente devuelve el PID y luego se ejecuta en segundo plano. (El eco $! asegura que no se devuelve nada más que el PID.) Esto permite que su script PHP continúe o salga si lo desea. Cuando he usado esto, he redirigido al usuario a otra página, donde cada 5 a 60 segundos se realiza una llamada AJAX para comprobar si el informe todavía se está ejecutando. (Tengo una mesa para almacena el gen_id y el usuario con el que está relacionado.) El script de comprobación ejecuta lo siguiente:

exec('ps ' . $pid , $processState);
if (count($processState) < 2) {
     // less than 2 rows in the ps, therefore report is complete
}

Hay un breve post sobre esta técnica aquí: http://nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/

 48
Author: Darryl Hein,
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-01-17 01:50:10

En resumen: sí, hay multihilo en php pero deberías usar multiprocesamiento en su lugar.

Backgroud info: threads vs procesos

Siempre hay un poco de confusión sobre la distinción de hilos y procesos, así que describiré brevemente ambos:

  • Un subproceso es una secuencia de comandos que la CPU procesará. El único dato en el que se compone es un contador de programas. Cada núcleo de CPU solo procesará un subproceso a la vez, pero puede cambiar entre ejecución de diferentes mediante programación.
  • Un proceso es un conjunto de recursos compartidos. Eso significa que consiste en una parte de memoria, variables, instancias de objetos, manejadores de archivos, mutexes, conexiones de base de datos, etc. Cada proceso también contiene uno o más hilos. Todos los subprocesos del mismo proceso comparten sus recursos, por lo que puede usar una variable en un subproceso que creó en otro. Si esos subprocesos son partes de dos procesos diferentes, entonces no pueden acceder entre sí recursos directamente. En este caso necesita comunicación entre procesos a través de, por ejemplo, tuberías, archivos, sockets...

Multiprocesamiento

Puede lograr la computación paralela creando nuevos procesos (que también contienen un nuevo hilo) con php. Si sus hilos no necesitan mucha comunicación o sincronización, esta es su elección, ya que los procesos están aislados y no pueden interferir con el trabajo de los demás. Incluso si uno se estrella, eso no concierne a los otros. Si lo haces necesita mucha comunicación, usted debe leer en "multithreading" o - tristemente-considerar el uso de otro lenguaje de programación, porque la comunicación entre procesos y la sincronización introduce una gran cantidad de tez.

En php tienes dos formas de crear un nuevo proceso:

Deje que el sistema operativo lo haga por usted: puede decirle a su sistema operativo que cree un nuevo proceso y ejecute un nuevo (o el mismo) script php en él.

  • Para linux puede utilizar lo siguiente o considere la respuesta de Darryl Hein :

    $cmd = 'nice php script.php 2>&1 & echo $!';
    pclose(popen($cmd, 'r'));
    
  • Para windows puede usar esto:

    $cmd = 'start "processname" /MIN /belownormal cmd /c "script.php 2>&1"';
    pclose(popen($cmd, 'r'));
    

Hágalo usted mismo con una bifurcación : php también proporciona la posibilidad de usar la bifurcación a través de la función pcntl_fork(). Un buen tutorial sobre cómo hacer esto se puede encontrar aquí pero recomiendo encarecidamente no usarlo, ya que fork es un crimen contra la humanidad y especialmente contra oop.

Multihilo

Con multithreading todos tus hilos comparten sus recursos para que puedas comunicarte fácilmente entre ellos y sincronizarlos sin mucha sobrecarga. Por otro lado, tienes que saber lo que estás haciendo, ya que las condiciones de carrera y los bloqueos son fáciles de producir pero muy difíciles de depurar.

Php estándar no proporciona ningún multihilo, pero hay una extensión (experimental) que realmente lo hace - pthreads. Su documentación api incluso hecho en php.net . Con él puedes hacer algunas cosas como puedes en lenguajes de programación reales : -) así:

class MyThread extends Thread {
    public function run(){
        //do something time consuming
    }
}

$t = new MyThread();
if($t->start()){
    while($t->isRunning()){
        echo ".";
        usleep(100);
    }
    $t->join();
}

Para linux hay una guía de instalación justo aquí en stackoverflow.

Para windows ahora hay uno:

  • Primero necesitas la versión de php segura para subprocesos.
  • Necesita las versiones precompiladas de ambos pthreads y su extensión php. Se pueden descargar aquí. Hacer seguro que descarga la versión que es compatible con su versión de php.
  • Copie php_pthreads.dll (desde el zip que acaba de descargar) en su carpeta de extensión php ([phpDirectory]/ext).
  • Copia pthreadVC2.dll en [phpDirectory] (la carpeta raíz - no la carpeta de extensión).
  • Editar [phpDirectory]/php.ini e insértese la línea siguiente

    extension=php_pthreads.dll
    
  • Pruébelo con el script anterior con un poco de sueño o algo allí donde el comentario ser.

Y ahora el gran PERO: Aunque esto realmente funciona, php no se hizo originalmente para multihilo. Existe una versión de php segura para subprocesos y a partir de la v5. 4 parece estar casi libre de errores, pero el uso de php en un entorno multiproceso sigue siendo desaconsejado en el manual de php (pero tal vez simplemente no actualizaron su manual sobre esto, todavía). Un problema mucho mayor podría ser que muchas extensiones comunes no son seguras para subprocesos. Así que usted podría conseguir los hilos con esta extensión php pero las funciones en las que estás dependiendo todavía no son seguros para hilos, por lo que probablemente encontrarás condiciones de carrera, bloqueos, etc. en código que no escribiste tú mismo...

 24
Author: Francois Bourgeois,
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
2017-05-23 12:26:22

Puedes usar pcntl_fork() para lograr algo similar a threads. Técnicamente se trata de procesos separados, por lo que la comunicación entre los dos no es tan simple con hilos, y creo que no funcionará si PHP es llamado por apache.

 17
Author: davr,
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-10-16 22:30:26

Si a alguien le importa, he revivido php_threading (no es lo mismo que threads, pero similar) y en realidad lo tengo hasta el punto en que funciona (de alguna manera) bien!

Página del Proyecto

Descargar (para Windows PHP 5.3 VC9 TS)

Ejemplos

README

 13
Author: Alec Gorge,
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-09-12 21:20:39

pcntl_fork() es lo que está buscando, pero su proceso de bifurcación no enhebrado. así que tendrá el problema del intercambio de datos. para resolverlos puedes usar funciones de semáforo phps ( http://www.php.net/manual/de/ref.sem.php ) las colas de mensajes pueden ser un poco más fáciles para el principio que los segmentos de memoria compartida.

De todos modos, una estrategia que estoy utilizando en un marco web que estoy desarrollando que carga bloques de recursos intensivos de una página web (probablemente con solicitudes externas) en paralelo: me estoy haciendo una cola de trabajo para saber qué datos estoy esperando y luego me bifurco de los trabajos para cada proceso. una vez hecho esto, almacenan sus datos en la caché de apc bajo una clave única a la que el proceso padre puede acceder. una vez que todos los datos están allí, continúa. estoy usando simple usleep() para esperar porque la comunicación entre procesos no es posible en apache (los niños perderán la conexión con sus padres y se convertirán en zombis...). así que esto me lleva a la última cosa: ¡es importante matar a cada niño! alli también son clases que bifurcan procesos pero mantienen datos, no los examiné, pero zend framework tiene uno, y generalmente hacen código lento pero confiable. puedes encontrarlo aquí: http://zendframework.com/manual/1.9/en/zendx.console.process.unix.overview.html creo que usan segmentos shm! bueno, por último, pero no menos importante, hay un error en este sitio web de zend, un error menor en el ejemplo.

while ($process1->isRunning() && $process2->isRunning()) {
    sleep(1);
}
should of course be:
while ($process1->isRunning() || $process2->isRunning()) {
    sleep(1);
}
 7
Author: The Surrican,
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
2011-11-03 12:27:57

Hay una extensión de roscado activley desarrollado basado en PThreads que parece muy prometedor en https://github.com/krakjoe/pthreads

 6
Author: JasonDavis,
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-24 04:38:17

Solo una actualización, parece que los chicos de PHP están trabajando en el hilo de soporte y está disponible ahora.

Aquí está el enlace a él: http://php.net/manual/en/book.pthreads.php

 6
Author: happyhardik,
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-09-14 15:28:27

Tengo una clase de subprocesos PHP que ha estado funcionando sin problemas en un entorno de producción durante más de dos años.

EDITAR: Ahora está disponible como una biblioteca composer y como parte de mi framework MVC, Hazaar MVC.

Véase: https://git.hazaarlabs.com/hazaar/hazaar-thread

 5
Author: Jamie Carl,
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
2016-09-01 00:04:01

Sé que esta es una pregunta antigua, pero podrías mirar http://phpthreadlib.sourceforge.net /

Comunicación bidireccional, soporte para Win32 y no se requieren extensiones.

 2
Author: Unsigned,
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
2011-02-23 15:44:14

¿Has oído hablar de appserver de techdivision?

Está escrito en php y funciona como un servidor de aplicaciones gestionando multihilos para aplicaciones php de alto tráfico. Todavía está en beta, pero muy promesing.

 1
Author: user2627170,
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-28 08:48:12

Existe la característica bastante oscura, y pronto a ser obsoleta, llamada ticks. Lo único para lo que lo he usado es para permitir que un script capture SIGKILL (Ctrl+C) y cierre con gracia.

 -3
Author: troelskn,
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-10-19 12:19:48