Come si può usare il multi threading nelle applicazioni PHP


414

Esiste un modo realistico di implementare un modello multi-thread in PHP, sia che si tratti di simularlo davvero o semplicemente. Qualche tempo fa è stato suggerito di forzare il sistema operativo a caricare un'altra istanza dell'eseguibile PHP e gestire altri processi simultanei.

Il problema è che quando il codice PHP ha terminato l'esecuzione dell'istanza PHP rimane in memoria perché non c'è modo di ucciderlo dall'interno di PHP. Quindi, se stai simulando diversi thread, puoi immaginare cosa accadrà. Quindi sto ancora cercando un modo per fare o simulare efficacemente il multi-threading all'interno di PHP. Qualche idea?


1
Vedere la mia domanda e le risposte qui: stackoverflow.com/questions/2101640/...
powtac



Forse di interesse: pthreads.org
GibboK,

Ora nel 2020, che sembra "parallelo" php.net/manual/en/intro.parallel.php è quello che vogliamo, invece di "pthreads": stackoverflow.com/a/56451969/470749
Ryan

Risposte:


431

Il multi-threading è possibile in php

Sì, puoi fare il multi-threading in PHP con pthreads

Dalla documentazione di PHP :

pthreads è un'API orientata agli oggetti che fornisce tutti gli strumenti necessari per il multi-threading in PHP. Le applicazioni PHP possono creare, leggere, scrivere, eseguire e sincronizzare con Thread, Worker e oggetti Threaded.

Avvertenza : l'estensione pthreads non può essere utilizzata in un ambiente web server. Il threading in PHP dovrebbe quindi rimanere solo per le applicazioni basate sulla CLI.

Test semplice

#!/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();
}

?>

Prima corsa

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

Seconda manche

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

Esempio del mondo reale

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);
}

3
@Baba, non sono in grado di configurare e installare pthreads sul server Xampp. Potete aiutarmi con quello?
Irfan,

4
Baba

17
È bello, non tocco PHP da anni e ora ha funzionalità di multithreading!
incrociatore

1
Bello e semplice! Per la sicurezza, sto distribuendo un'app sul server Azure Cloud Win e se viene selezionata solo la configurazione di base 1 core, il multi-thread non sarà disponibile a meno che non vengano aggiunti più core.
Milano,

3
Attenzione: Joe Watkins, l'autore dell'estensione pthreads ha interrotto lo sviluppo a favore della nuova estensione parallela: github.com/krakjoe/pthreads/issues/929
Anton Belonovich,

42

perché non usi popen ?

for ($i=0; $i<10; $i++) {
    // open ten processes
    for ($j=0; $j<10; $j++) {
        $pipe[$j] = popen('script2.php', 'w');
    }

    // wait for them to finish
    for ($j=0; $j<10; ++$j) {
        pclose($pipe[$j]);
    }
}

4
Sto usando la soluzione sopra e funziona bene, penso che sia stato il modo più semplice per fare un processo parallelo usando php.
GodFather

7
come ha detto @ e-info128, questa implementazione prevede il processo, il che significa che è in esecuzione su un processo diverso e non condivide le risorse del processo. Detto questo, se il lavoro da svolgere non ha bisogno di condividere le risorse, funzionerà comunque e funzionerà in parallelo.
Raffi

1
Come passereste le variabili per visualizzarle senza usare le variabili di sessione?
atwellpub,

@atwellpub In nessun caso, si tratta di processi separati che non condividono risorse. Anche le sessioni saranno un meccanismo imbarazzante dell'IPC
Cholthi Paul Ttiopic,

1
Per passare loro i dati, puoi usare anche gli argomenti e il server Redis.
Amir Fo

21

Il threading non è disponibile nello stock PHP, ma è possibile una programmazione simultanea utilizzando le richieste HTTP come chiamate asincrone.

Con l'impostazione del timeout del ricciolo impostata su 1 e utilizzando lo stesso session_id per i processi che si desidera associare tra loro, è possibile comunicare con le variabili di sessione come nell'esempio seguente. Con questo metodo puoi persino chiudere il browser e il processo simultaneo esiste ancora sul server.

Non dimenticare di verificare l'ID sessione corretto in questo modo:

http: //localhost/test/verifysession.php? sessionid = [l' id corretto]

startprocess.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"];

process1.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);
}

verifysession.php

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

session_start();
var_dump($_SESSION);

closeprocess.php

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

session_start();
$_SESSION["closesession"] = true;
var_dump($_SESSION);

4
L'ultima volta che ho controllato (qualche anno fa) php non mi ha permesso di accedere allo storage di sessione basato su file da due processi contemporaneamente. Blocca il file e il secondo processo deve rimanere lì in attesa dell'arresto del primo script. Sto parlando dell'ambiente del server web, non della CLI.
Alexei Tenitski,

5
set_time_limit(0);yikes! Mai e poi mai.
Kafoso,

@Kafoso Kafoso perché no? Bene, sono d'accordo con PHP come elaboratore di script Web, ma perché non nella CLI? Se qualcosa va storto, CLI può essere ucciso con Ctrl + C ...
sijanec

14

Anche se non puoi thread, hai un certo grado di controllo del processo in php. I due set di funzioni utili qui sono:

Funzioni di controllo del processo http://www.php.net/manual/en/ref.pcntl.php

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

È possibile eseguire il fork del processo con pcntl_fork, restituendo il PID del bambino. Quindi puoi utilizzare posix_kill per deselezionare quel PID.

Detto questo, se si uccide un processo genitore, è necessario inviare un segnale al processo figlio che gli dice di morire. Se php stesso non lo riconosce, è possibile registrare una funzione per gestirla e fare un'uscita pulita usando pcntl_signal.


1
Quella risposta è ora molto obsoleta (il che è molto giusto sapendo che ha 11 anni). Guarda qui sotto.
Maciej Paprocki,

@MaciejPaprocki pThread non è più in produzione a partire da 7,4 invece di usare parallelo
Airy


10

So che questa è una vecchia domanda, ma per le persone che cercano, c'è un'estensione PECL scritta in C che ora offre funzionalità multi-threading PHP, si trova qui https://github.com/krakjoe/pthreads


pThread è ora interrotto da php 7.4 invece usa parallel
Airy

5

È possibile utilizzare exec () per eseguire uno script da riga di comando (come riga di comando php) e se si esegue il pipe dell'output in un file, lo script non attenderà il completamento del comando.

Non ricordo bene la sintassi della CLI php, ma vorresti qualcosa del tipo:

exec("/path/to/php -f '/path/to/file.php' | '/path/to/output.txt'");

Penso che alcuni server di hosting condiviso abbiano exec () disabilitato di default per motivi di sicurezza, ma potrebbe valere la pena provarlo.


4

Potresti simulare il threading. PHP può eseguire processi in background tramite popen (o proc_open). Tali processi possono essere comunicati tramite stdin e stdout. Naturalmente questi processi possono essere essi stessi un programma php. Questo è probabilmente il più vicino possibile.


3

A seconda di ciò che stai cercando di fare, puoi anche usare curl_multi per raggiungerlo.



3

Puoi avere l'opzione di:

  1. multi_curl
  2. Si può usare il comando di sistema per lo stesso
  3. Lo scenario ideale è creare una funzione di threading in linguaggio C e compilare / configurare in PHP. Ora quella funzione sarà la funzione di PHP.


3

Che ne dici di pcntl_fork?

controlla la nostra pagina di manuale per esempi: PHP pcntl_fork

<?php

    $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
    }

?>

2

pcntl_forknon funzionerà in un ambiente web server se è attiva la modalità provvisoria . In questo caso, funzionerà solo nella versione CLI di PHP.


1

Se si utilizza un server Linux, è possibile utilizzare

exec("nohup $php_path path/script.php > /dev/null 2>/dev/null &")

Se hai bisogno di passare alcuni argomenti

exec("nohup $php_path path/script.php $args > /dev/null 2>/dev/null &")

In script.php

$args = $argv[1];

Oppure usa Symfony https://symfony.com/doc/current/components/process.html

$process = Process::fromShellCommandline("php ".base_path('script.php'));
$process->setTimeout(0);     
$process->disableOutput();     
$process->start();

-1

Al momento della stesura del mio attuale commento, non conosco i thread di PHP. Sono venuto qui per cercare la risposta da solo, ma una soluzione alternativa è che il programma PHP che riceve la richiesta dal server Web delega l'intera formulazione di risposta a un'applicazione console che memorizza il suo output, la risposta alla richiesta, in un file binario e il programma PHP che ha lanciato l'applicazione console restituisce quel file binario byte per byte come risposta alla richiesta ricevuta. L'applicazione console può essere scritta in qualsiasi linguaggio di programmazione in esecuzione sul server, compresi quelli che dispongono del supporto di threading appropriato, inclusi i programmi C ++ che utilizzano OpenMP.

Un trucco inaffidabile, sporco, è usare PHP per eseguire un'applicazione console, "uname",

uname -a

e stampa l'output del comando console sull'output HTML per scoprire la versione esatta del software server. Quindi installa la stessa identica versione del software in un'istanza di VirtualBox, compila / assembla qualsiasi binario completamente autonomo, preferibilmente statico, che desideri e poi carica quelli sul server. Da quel momento in poi l'applicazione PHP può usare quei binari nel ruolo dell'applicazione console che ha il multi-threading corretto. È una soluzione sporca, inaffidabile, alternativa a una situazione, quando l'amministratore del server non ha installato sul server tutte le implementazioni del linguaggio di programmazione necessarie. La cosa a cui prestare attenzione è che ad ogni richiesta che l'applicazione PHP riceve le applicazioni console termina / esci / get_killed.

Per quanto riguarda ciò che gli amministratori del servizio di hosting pensano di tali modelli di utilizzo del server, immagino si riduca alla cultura. Nel Nord Europa il fornitore di servizi DEVE CONSEGNARE CHE COSA È STATO PUBBLICATO e se è stata consentita l'esecuzione di comandi della console e è stato consentito il caricamento di file non malware e il fornitore di servizi ha il diritto di interrompere qualsiasi processo server dopo pochi minuti o anche dopo 30 secondi , quindi gli amministratori del servizio di hosting non hanno argomenti per formulare un reclamo adeguato. Negli Stati Uniti e in Europa occidentale la situazione / cultura è molto diversa e credo che ci sia una grande possibilità che negli Stati Uniti e / o in Europa occidentale il fornitore di servizi di hosting si rifiuti di servire i clienti di servizi di hosting che usano il trucco sopra descritto. È solo una mia ipotesi, data la mia esperienza personale con gli Stati Uniti servizi di hosting e dati ciò che ho sentito da altri sui servizi di hosting dell'Europa occidentale. Al momento della stesura del mio attuale commento (2018_09_01) non so nulla delle norme culturali dei fornitori di servizi di hosting dell'Europa meridionale, amministratori di rete dell'Europa meridionale.


-3

Forse mi sono perso qualcosa, ma exec non ha funzionato come asincrono per me in ambiente Windows che ho usato seguendo in Windows e ha funzionato come un fascino;)

$script_exec = "c:/php/php.exe c:/path/my_ascyn_script.php";

pclose(popen("start /B ". $script_exec, "r"));

1
Per hackerare il multithreading in PHP è necessario aprire più istruzioni popen () (PHP non attenderà il completamento). Quindi, dopo una mezza dozzina circa, si chiama pclose () su quelli (PHP attenderà il completamento di pclose ()). Nel tuo codice chiudi ogni thread immediatamente dopo averlo aperto in modo che il tuo codice non si comporti come multithread.
Kmeixner,

-5

Multithreading significa eseguire più attività o processi contemporaneamente, possiamo raggiungere questo obiettivo in php usando il seguente codice, anche se non esiste un modo diretto per ottenere il multithreading in php ma possiamo ottenere quasi gli stessi risultati seguendo il modo.

chdir(dirname(__FILE__));  //if you want to run this file as cron job
 for ($i = 0; $i < 2; $i += 1){
 exec("php test_1.php $i > test.txt &");
 //this will execute test_1.php and will leave this process executing in the background and will go         

 //to next iteration of the loop immediately without waiting the completion of the script in the   

 //test_1.php , $i  is passed as argument .

}

Test_1.php

$conn=mysql_connect($host,$user,$pass);
$db=mysql_select_db($db);
$i = $argv[1];  //this is the argument passed from index.php file
for($j = 0;$j<5000; $j ++)
{
mysql_query("insert  into  test   set

                id='$i',

                comment='test',

                datetime=NOW() ");

}

Questo eseguirà test_1.php due volte contemporaneamente ed entrambi i processi verranno eseguiti contemporaneamente in background, quindi in questo modo puoi ottenere il multithreading in php.

Questo ragazzo ha fatto davvero un buon lavoro Multithreading in php


Inoltre, questo non ha nulla a che fare con MultiThreading. Questa è l'elaborazione parallela. Cose totalmente diverse.
Digital Human,

A mio avviso come una soluzione alternativa, un hack di emergenza, l'idea alla base della soluzione offerta è molto appropriata, ma immagino che persone diverse possano avere guerre di fiamma su ciò che costituisce il "vero multi-threading", perché esiste una distinzione tra concorrenza e basata su hardware elaborazione parallela, come descritto su: youtube.com/watch?v=cN_DpYBzKso
Martin Vahi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.