¿Cómo se pueden utilizar subprocesos múltiples en aplicaciones PHP?

Resuelto Steve Obbayi asked hace 54 años • 0 respuestas

¿Existe una forma realista de implementar un modelo multiproceso en PHP, ya sea de verdad o simplemente simulándolo? Hace algún tiempo se sugirió que se podía forzar al sistema operativo a cargar otra instancia del ejecutable PHP y manejar otros procesos simultáneos.

El problema con esto es que cuando el código PHP termina de ejecutarse, la instancia de PHP permanece en la memoria porque no hay forma de eliminarla desde PHP. Entonces, si estás simulando varios hilos, puedes imaginar lo que sucederá. Por lo tanto, todavía estoy buscando una forma de realizar o simular de manera efectiva el subproceso múltiple desde PHP. ¿Algunas ideas?

Steve Obbayi avatar Jan 01 '70 08:01 Steve Obbayi
Aceptado

Advertencia : esta extensión se considera sin mantenimiento y muerta. Advertencia: la extensión pthreads no se puede utilizar en un entorno de servidor web. Por lo tanto, el subproceso en PHP está restringido únicamente a aplicaciones basadas en CLI. Advertencia : pthreads (v3) solo se puede usar con PHP 7.2+: esto se debe a que el modo ZTS no es seguro en 7.0 y 7.1.

https://www.php.net/manual/en/intro.pthreads.php


El subproceso múltiple es posible en php

Sí, puedes hacer subprocesos múltiples en PHP con pthreads

De la documentación de PHP :

pthreads es una API orientada a objetos que proporciona todas las herramientas necesarias para subprocesos múltiples en PHP. Las aplicaciones PHP pueden crear, leer, escribir, ejecutar y sincronizar con Threads, Workers y objetos Threaded.

Advertencia : la extensión pthreads no se puede utilizar en un entorno de servidor web. Por lo tanto, la creación de subprocesos en PHP debería limitarse a aplicaciones basadas en CLI.

Prueba sencilla

#!/usr/bin/php
<?php
class AsyncOperation extends Thread {

    public function __construct($arg) {
        $this->arg = $arg;
    }

    public function run() {
        if ($this->arg) {
            $sleep = mt_rand(1, 10);
            printf('%s: %s  -start -sleeps %d' . "\n", date("g:i:sa"), $this->arg, $sleep);
            sleep($sleep);
            printf('%s: %s  -finish' . "\n", date("g:i:sa"), $this->arg);
        }
    }
}

// Create a array
$stack = array();

//Initiate Multiple Thread
foreach ( range("A", "D") as $i ) {
    $stack[] = new AsyncOperation($i);
}

// Start The Threads
foreach ( $stack as $t ) {
    $t->start();
}

?>

Primer intento

12:00:06pm:     A  -start -sleeps 5
12:00:06pm:     B  -start -sleeps 3
12:00:06pm:     C  -start -sleeps 10
12:00:06pm:     D  -start -sleeps 2
12:00:08pm:     D  -finish
12:00:09pm:     B  -finish
12:00:11pm:     A  -finish
12:00:16pm:     C  -finish

Segunda carrera

12:01:36pm:     A  -start -sleeps 6
12:01:36pm:     B  -start -sleeps 1
12:01:36pm:     C  -start -sleeps 2
12:01:36pm:     D  -start -sleeps 1
12:01:37pm:     B  -finish
12:01:37pm:     D  -finish
12:01:38pm:     C  -finish
12:01:42pm:     A  -finish

Ejemplo del mundo real

error_reporting(E_ALL);
class AsyncWebRequest extends Thread {
    public $url;
    public $data;

    public function __construct($url) {
        $this->url = $url;
    }

    public function run() {
        if (($url = $this->url)) {
            /*
             * If a large amount of data is being requested, you might want to
             * fsockopen and read using usleep in between reads
             */
            $this->data = file_get_contents($url);
        } else
            printf("Thread #%lu was not provided a URL\n", $this->getThreadId());
    }
}

$t = microtime(true);
$g = new AsyncWebRequest(sprintf("http://www.google.com/?q=%s", rand() * 10));
/* starting synchronization */
if ($g->start()) {
    printf("Request took %f seconds to start ", microtime(true) - $t);
    while ( $g->isRunning() ) {
        echo ".";
        usleep(100);
    }
    if ($g->join()) {
        printf(" and %f seconds to finish receiving %d bytes\n", microtime(true) - $t, strlen($g->data));
    } else
        printf(" and %f seconds to finish, request failed\n", microtime(true) - $t);
}
Baba avatar Mar 19 '2013 13:03 Baba

Los subprocesos no están disponibles en PHP estándar, pero la programación simultánea es posible mediante el uso de solicitudes HTTP como llamadas asincrónicas.

Con la configuración de tiempo de espera de curl establecida en 1 y usando el mismo session_id para los procesos que desea asociar entre sí, puede comunicarse con las variables de sesión como en mi ejemplo a continuación. Con este método puedes incluso cerrar tu navegador y el proceso concurrente aún existirá en el servidor.

No olvide verificar el ID de sesión correcto de esta manera:

http://localhost/test/verifysession.php?sessionid=[la identificación correcta]

iniciarproceso.php

$request = "http://localhost/test/process1.php?sessionid=".$_REQUEST["PHPSESSID"];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_exec($ch);
curl_close($ch);
echo $_REQUEST["PHPSESSID"];

proceso1.php

set_time_limit(0);

if ($_REQUEST["sessionid"])
   session_id($_REQUEST["sessionid"]);

function checkclose()
{
   global $_SESSION;
   if ($_SESSION["closesession"])
   {
       unset($_SESSION["closesession"]);
       die();
   }
}

while(!$close)
{
   session_start();
   $_SESSION["test"] = rand();
   checkclose();
   session_write_close();
   sleep(5);
}

verificarsesion.php

if ($_REQUEST["sessionid"])
    session_id($_REQUEST["sessionid"]);

session_start();
var_dump($_SESSION);

cerrarproceso.php

if ($_REQUEST["sessionid"])
    session_id($_REQUEST["sessionid"]);

session_start();
$_SESSION["closesession"] = true;
var_dump($_SESSION);
Ricardo avatar Jul 03 '2009 14:07 Ricardo

Si bien no puedes enhebrar, tienes cierto grado de control de procesos en php. Los dos conjuntos de funciones que son útiles aquí son:

Funciones de control de procesos http://www.php.net/manual/en/ref.pcntl.php

Funciones POSIX http://www.php.net/manual/en/ref.posix.php

Puede bifurcar su proceso con pcntl_fork, devolviendo el PID del niño. Luego puedes usar posix_kill para deshacerte de ese PID.

Dicho esto, si mata un proceso padre, se debe enviar una señal al proceso hijo diciéndole que muera. Si PHP no reconoce esto, puede registrar una función para administrarlo y realizar una salida limpia usando pcntl_signal.

J.D. Fitz.Gerald avatar Sep 16 '2008 10:09 J.D. Fitz.Gerald