¿Tiene PHP enhebrado?
multithreading apache (13)
¿Alguna vez escuchó sobre el appserver
de aplicaciones de techdivision?
Está escrito en php y funciona como un servidor de aplicaciones que gestiona multithreads para aplicaciones de php de alto tráfico. Todavía está en beta pero muy prometedor.
Encontré este paquete PECL llamado threads , pero todavía no hay un lanzamiento. Y nada está por aparecer en el sitio web de PHP.
Aquí hay un ejemplo de lo que sugirió Wilco:
$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. (The echo $! Garantiza que no se devuelve nada más que el PID). Esto permite que su script PHP continúe o salga si lo desea. Cuando lo he usado, he redirigido al usuario a otra página, donde cada 5 a 60 segundos se realiza una llamada AJAX para verificar si el informe aún se está ejecutando. (Tengo una tabla para almacenar el gen_id y el usuario al que está relacionado). El script de verificación ejecuta lo siguiente:
exec(''ps '' . $pid , $processState);
if (count($processState) < 2) {
// less than 2 rows in the ps, therefore report is complete
}
Hay una breve publicación sobre esta técnica aquí: http://nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/
Del manual PHP para la extensión pthreads :
pthreads es una API orientada a objetos que permite multihilo de usuario-tierra en PHP. Incluye todas las herramientas que necesita para crear aplicaciones multiproceso dirigidas a la Web o la consola. Las aplicaciones PHP pueden crear, leer, escribir, ejecutar y sincronizar con Threads, Workers y Stackables.
Tan increíble como suena, es completamente cierto. En la actualidad, PHP puede ofrecer múltiples hilos para aquellos que deseen probarlo.
La primera versión de PHP4, 22 de mayo de 2000, PHP se envió con una arquitectura segura para hilos: una forma de ejecutar varias instancias de su intérprete en subprocesos separados en entornos SAPI (API de servidor) de subprocesos múltiples. En 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.
Enhebrar en tierra del usuario nunca fue una preocupación para el equipo de PHP, y permanece como tal hoy. Debe comprender que en el mundo en el que PHP opera, ya existe 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 barato y más barato, por lo que se convirtió en una preocupación cada vez menor para el equipo de PHP. Si bien se estaba volviendo más barato, también se volvió mucho más poderoso; hoy, nuestros teléfonos móviles y tabletas tienen arquitecturas de doble y cuádruple núcleo y mucha RAM para usar, nuestros equipos de escritorio y servidores comúnmente tienen 8 o 16 núcleos, 16 y 32 gigabytes de RAM, aunque es posible que no siempre podamos tener dos dentro del presupuesto y tener dos computadoras de escritorio rara vez es útil para la mayoría de nosotros.
Además, PHP fue escrito para el no programador, es muchos aficionados a la lengua nativa. La razón por la que PHP se adopta tan fácilmente es porque es un lenguaje fácil de aprender y escribir. La razón por la cual PHP es tan confiable hoy en día se debe a la gran cantidad de trabajo que se destina a su diseño y a cada decisión que toma el grupo de PHP. Es la fiabilidad y la grandeza pura mantenerlo en el foco, después de todos estos años; donde sus rivales han caído en el tiempo o la presión.
La programación de subprocesos múltiples 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 de PHP no desea que el uso del multihilo del usuario sea una característica central, nunca se le ha prestado mucha atención, y con razón. PHP no debe ser complejo, para todos.
Teniendo en cuenta todo lo anterior, todavía hay beneficios al permitir que PHP utilice sus funciones preparadas y probadas de producción para permitir una forma de aprovechar al máximo lo que tenemos, cuando agregar más no siempre es una opción, y por mucho de tareas nunca es realmente necesario.
pthreads logra, para aquellos que desean explorarlo, una API que permite que un usuario multiplique las aplicaciones de PHP. Su API es un trabajo en progreso y ha designado un nivel beta de estabilidad e integridad.
Es de conocimiento común que algunas de las bibliotecas que PHP usa no son seguras para hilos, debe quedar claro para el programador que pthreads no puede cambiar esto y no intenta intentarlo. Sin embargo, cualquier biblioteca que sea segura para hilos es utilizable, como en cualquier otra configuración segura para hilos del intérprete.
pthreads utiliza Posix Threads (incluso en Windows), lo que el programador crea son hilos de ejecución reales, pero para que esos hilos sean útiles, deben ser conscientes de PHP: capaces 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 de API de servidor de subprocesos múltiples. pthreads intenta cerrar la brecha de una manera sana y segura. Muchas de las preocupaciones del programador de subprocesos en C simplemente no están ahí para el programador de pthreads, por diseño, pthreads es copy on read y copy on write (RAM es barato), por lo que no hay dos instancias que manipulen los mismos datos físicos , pero ambos pueden afectar los datos en otro hilo. El hecho de que PHP pueda usar funciones inseguras de subprocesos en su programación central es totalmente irrelevante, los hilos 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 que un bloqueo de lectura y escritura se mantienen en el almacén de datos de objetos pthreads, los datos se copian de su ubicación original en la memoria al almacén de objetos. pthreads no ajusta el recuento de la variable, Zend puede liberar los datos originales si no hay más referencias al mismo.
(2) El argumento de someOperation hace referencia al almacén de objetos, los datos originales almacenados, que a su vez son una copia del resultado de (1), se copian nuevamente para el motor en un contenedor zval, mientras esto ocurre, se mantiene un bloqueo de lectura el almacén de objetos, se libera el bloqueo y el motor puede ejecutar la función. Cuando se crea el zval, tiene un recuento de 0, lo que permite que el motor libere la copia al finalizar la operación, porque no existen otras referencias a ella.
(3) El último argumento para 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, nuevamente con un refcount de 0. Se libera el bloqueo, la llamada a preg_match opera en una copia de datos, que a su vez es una copia de los datos originales.
Cosas que saber:
La tabla hash del almacén de objetos donde se almacenan los datos, es segura para los hilos,
basado en el TsHashTable enviado con PHP, por Zend.El almacén de objetos tiene un bloqueo de lectura y escritura, se proporciona un bloqueo de acceso adicional para TsHashTable de modo que si es necesario (y lo hace, var_dump / print_r, acceso directo a las propiedades ya que el motor PHP quiere hacer referencia a ellos) pthreads puede manipular TsHashTable fuera de la API definida.
Los bloqueos solo se mantienen mientras se realizan las operaciones de copia, cuando las copias se han realizado, se liberan los bloqueos, en un orden razonable.
Esto significa:
Cuando se produce una escritura, no solo se mantiene un bloqueo de lectura y escritura, sino también un bloqueo de acceso adicional. La tabla en sí está bloqueada, no hay forma posible de que otro contexto pueda bloquearla, leerla, escribirla o afectarla.
Cuando se produce una lectura, no solo se mantiene el bloqueo de lectura, sino que también se bloquea el acceso adicional, nuevamente la tabla se bloquea.
No hay dos contextos que puedan acceder física o simultáneamente a los mismos datos desde el almacén de objetos, pero las escrituras hechas en cualquier contexto con una referencia afectarán la lectura de datos en cualquier contexto con una referencia.
Esto no es nada compartido arquitectura y la única manera de existir es coexistir. Aquellos que sean un poco listos verán que hay muchas copias aquí, y se preguntarán si eso es algo bueno. Se realizan muchas copias dentro de un tiempo de ejecución dinámico, esa es la dinámica de un lenguaje dinámico. pthreads se implementa en el 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 bloqueos y copias, el alcance del método local. El alcance 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 con hebras en lugar de hacer que se copien desde el almacén de objetos en la ejecución.
La mayoría de las bibliotecas y extensiones disponibles para PHP son envolturas delgadas alrededor de terceros, la funcionalidad básica de PHP hasta cierto punto es lo mismo. pthreads no es una envoltura delgada alrededor de Posix Threads; es una API de subprocesos basada en Posix Threads. No tiene sentido implementar Threads en PHP que sus usuarios no entienden o no pueden usar. No hay ninguna razón para que una persona que no tiene conocimiento de lo que es un mutex o no pueda aprovechar todo lo que tiene, tanto en términos de habilidades como de recursos. Un objeto funciona como un objeto, pero dondequiera que dos contextos colisionen de otra manera, pthreads proporciona estabilidad y seguridad.
Cualquiera que haya trabajado en Java verá las similitudes entre un objeto pthreads y el enrutamiento en java, esas mismas personas habrán visto sin duda un error llamado ConcurrentModificationException, ya que suena un error planteado por el tiempo de ejecución java si dos hilos escriben los mismos datos físicos al mismo tiempo. 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 puede lograr la seguridad para el usuario, que opta por lanzar un error posiblemente fatal en tiempo de ejecución en lugar de administrar la ejecución y el acceso a los datos.
No se emitirán errores tan estúpidos por pthreads, la API está escrita para hacer que el hilo 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 ejemplos enviados con pthreads.
Por último, desde el manual de PHP:
pthreads fue, y es, un experimento con muy buenos resultados. Cualquiera de sus limitaciones o características puede 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 para la multitarea en PHP en cualquier nivel. En el entorno en el que pthreads se ejecuta, algunas restricciones y limitaciones son necesarias para proporcionar un entorno estable.
En resumen: sí, hay multithreading en php, pero debería usar multiproceso en su lugar.
Backgroud info: hilos frente a procesos
Siempre hay un poco de confusión sobre la distinción de hilos y procesos, así que describiré brevemente ambos:
- Un hilo es una secuencia de comandos que la CPU procesará. La única información que contiene es un contador de programa. Cada núcleo de la CPU solo procesará un hilo a la vez, pero puede cambiar entre la ejecución de los diferentes a través de la programación.
- Un proceso es un conjunto de recursos compartidos. Eso significa que consiste en una parte de la memoria, variables, instancias de objetos, manejadores de archivos, mutexes, conexiones de bases de datos, etc. Cada proceso también contiene uno o más hilos. Todos los hilos del mismo proceso comparten sus recursos, por lo que puede usar una variable en un hilo que haya creado en otro. Si esos hilos son parte de dos procesos diferentes, entonces no pueden acceder directamente a los recursos de los demás. En este caso, necesita comunicación entre procesos a través, por ejemplo, tuberías, archivos, enchufes ...
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 falla, eso no se aplica a los demás. Si necesita mucha comunicación, debe leer en "multihilo" o, lamentablemente, considerar el uso de otro lenguaje de programación, porque la comunicación y sincronización entre procesos introduce mucha 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 usar lo siguiente o considerar 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 un tenedor : php también ofrece la posibilidad de utilizar el bifurcación a través de la función pcntl_fork() . Un buen tutorial sobre cómo hacer esto se puede encontrar here pero recomiendo no usarlo, ya que tenedor es un crimen contra la humanidad y especialmente contra oop.
Multihilo
Con el subprocesamiento múltiple, todos los subprocesos comparten sus recursos para que pueda comunicarse fácilmente y sincronizarlos sin tener que cargar demasiados recursos. Por otro lado, debe saber lo que está haciendo, ya que las condiciones de carrera y los interbloqueos son fáciles de producir pero muy difíciles de depurar.
El php estándar no proporciona ningún subprocesamiento múltiple, pero hay una extensión (experimental) que en realidad lo hace - pthreads . Su documentación api incluso llegó a php.net . Con él puedes hacer algunas cosas como puedas en lenguajes de programación reales :-) de esta manera:
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 aquí en .
Para Windows hay uno ahora:
- Primero necesitas la versión de php segura para subprocesos.
- Necesita las versiones pre compiladas de ambos pthreads y su extensión php. Pueden ser descargados here . Asegúrese de descargar la versión que sea compatible con su versión de php.
- Copie php_pthreads.dll (desde el archivo zip que acaba de descargar) en la carpeta de extensiones de php ([phpDirectory] / ext).
- Copie pthreadVC2.dll en [phpDirectory] (la carpeta raíz, no la carpeta de extensiones).
Edite [phpDirectory] /php.ini e inserte la siguiente línea
extension=php_pthreads.dll
Pruébalo con el script de arriba con algo de sueño o algo allí donde está el comentario.
Y ahora el gran PERO : aunque esto realmente funciona, php no fue hecho originalmente para multihilo. Existe una versión de php segura para subprocesos y, a partir de v5.4, parece estar casi libre de fallos, pero el uso de php en un entorno de subprocesos múltiples todavía se desaconseja en el manual de php (pero tal vez simplemente no actualizaron su manual en esto, aún). Un problema mucho más grande podría ser que muchas extensiones comunes no son seguras para subprocesos . Por lo tanto, puede obtener hilos con esta extensión de php, pero las funciones de las que depende aún no son seguras para subprocesos, por lo que probablemente encontrará condiciones de carrera, interbloqueos, etc. en un código que no escribió usted mismo ...
Existe la característica bastante oscura, que pronto será obsoleta, llamada ticks . Para lo único que lo he usado, es permitir que un script capture SIGKILL (Ctrl + C) y cerrar con gracia.
Hay una extensión de Threading desarrollada en función de PThreads que se ve muy prometedora en pthreads
No hay nada disponible que yo sepa. Lo mejor sería simplemente hacer que un script ejecute otro mediante CLI, pero eso es un poco rudimentario. Dependiendo de lo que intente hacer y cuán complejo sea, esto puede ser o no una opción.
Puede usar pcntl_fork() para lograr algo similar a los hilos. Técnicamente son procesos separados, por lo que la comunicación entre los dos no es tan sencilla con los hilos, y creo que no funcionará si Apache llama a PHP.
Sé que esta es una pregunta muy antigua, pero podrían consultar http://phpthreadlib.sourceforge.net/
Comunicación bidireccional, soporte para Win32 y no se requieren extensiones.
Si a alguien le importa, he revivido php_threading (no lo mismo que hilos, pero similar) y realmente lo tengo al punto donde funciona (algo) bien!
Solo una actualización, parece que los chicos de PHP están trabajando en el hilo de apoyo y está disponible ahora.
Aquí está el enlace: php.net
Tengo una clase de enhebrado PHP que se ha estado ejecutando sin problemas en un entorno de producción durante más de dos años.
EDITAR: Ahora está disponible como una biblioteca de compositores y como parte de mi marco MVC, Hazaar MVC.
pcntl_fork()
es lo que está buscando, pero su proceso no está bifurcando. entonces tendrá el problema del intercambio de datos. para resolverlos puede usar funciones de semáforo de phps ( http://www.php.net/manual/de/ref.sem.php ) las colas de mensajes pueden ser un poco más fáciles para el comienzo que los segmentos de memoria compartida.
De todos modos, una estrategia que estoy usando en un framework web que estoy desarrollando y que carga bloques de recursos intensivos de una página web (probablemente con solicitudes externas) paralelos: estoy haciendo una cola de trabajos para saber qué información estoy esperando y luego me meto fuera de los trabajos para cada proceso. una vez hecho, almacenan sus datos en la memoria caché de la APC bajo una clave única a la que el proceso principal puede acceder. una vez que todos los datos estén allí, continúa. Estoy usando usleep()
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 lo último: ¡es importante matar a cada uno de los niños! También hay clases que organizan procesos pero guardan datos, no los examiné, pero Zend Framework tiene uno, y generalmente hacen que el código sea lento pero confiable. puedes encontrarlo aquí: http://zendframework.com/manual/1.9/en/zendx.console.process.unix.overview.html creo que usan segmentos de shm! Bueno, por último pero no menos importante, hay un error en este sitio web zend, error menor en el ejemplo.
while ($process1->isRunning() && $process2->isRunning()) {
sleep(1);
}
should of course be:
while ($process1->isRunning() || $process2->isRunning()) {
sleep(1);
}