it-swarm.it

Come si può usare il multi-threading in PHP applicazioni

Esiste un modo realistico per implementare un modello multi-thread in PHP sia vero che simulato. Qualche volta è stato suggerito che è possibile forzare il sistema operativo a caricare un'altra istanza dell'eseguibile PHP e gestire altri processi simultanei.

Il problema è che quando il codice PHP termina di eseguire l'istanza PHP rimane in memoria perché non c'è modo di ucciderlo da PHP. Quindi, se stai simulando diversi thread, puoi immaginare che cosa accadrà. Quindi sto ancora cercando un modo in cui il multi-threading può essere fatto o simulato in modo efficace da PHP. Qualche idea?

366
Steve Obbayi

La multi-threading è possibile in php

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

Da la PHP documentazione :

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

Avviso : l'estensione pthreads non può essere utilizzata in un ambiente del server web. L'inserimento di PHP dovrebbe pertanto rimanere solo per le applicazioni basate su 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 corsa

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 di 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);
}
391
Baba

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]);
    }
}
34
masterb

Il threading non è disponibile in PHP, ma la programmazione concorrente è possibile utilizzando le richieste HTTP come chiamate asincrone.

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

Non dimenticare di verificare l'ID di 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);
18
Ricardo

Mentre non puoi eseguire il thread, hai un certo grado di controllo del processo in PHP. I due set di funzioni che sono 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 figlio. Quindi puoi usare posix_kill per desporre di quel PID.

Detto questo, se uccidi un processo genitore, un segnale dovrebbe essere inviato al processo figlio che gli dice di morire. Se PHP non riconosce questo, potresti registrare una funzione per gestirla e fare un'uscita pulita usando pcntl_signal.

11
J.D. Fitz.Gerald

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

8
JasonDavis

l'utilizzo dei thread è reso possibile dall'estensione PECL pthreads

http://www.php.net/manual/en/book.pthreads.php

8
pinkal vansia

Potresti simulare il threading. PHP può eseguire processi in background tramite popen (o proc_open). Questi processi possono essere comunicati con stdin e stdout. Ovviamente quei processi possono essere essi stessi un programma php. Probabilmente è il più vicino possibile.

5
Pete

È possibile utilizzare exec () per eseguire uno script da riga di comando (ad esempio, riga di comando php) e se si reindirizza l'output a un file, lo script non attende il completamento del comando.

Non riesco a ricordare 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 parecchi server di hosting condivisi abbiano exec () disabilitato di default per motivi di sicurezza, ma potrebbe valere la pena di provarlo.

5
Adam Hopkinson

Che ne dici di pcntl_fork?

controlla la nostra pagina di manuale per esempi: PHP pcntl_fork

3
Jarrod

A seconda di ciò che stai cercando di fare, potresti anche usare curl_multi per realizzarlo.

3
Sheldmandu

So che è molto vecchio, ma puoi guardare http://phpthreadlib.sourceforge.net/

Supporta la comunicazione inter-thread bidirezionale e ha anche protezioni integrate per eliminare i thread figli (prevenendo gli orfani).

3
Unsigned

pcntl_fork non funzionerà in un ambiente di server web se ha safe mode attivato. In questo caso, funzionerà solo nella versione CLI di PHP.

2
Stilero

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.
2
Manoj Donga

La classe Thread è disponibile dal PECL pthreads ≥ 2.0.0.

2

Al momento della stesura del mio commento corrente, non conosco i thread PHP. Sono venuto qui per cercare la risposta, ma una soluzione è che il programma PHP che riceve la richiesta dal server Web delega l'intera formulazione della risposta a un'applicazione della console che memorizza il suo output, la risposta al richiesta, in un file binario e il programma PHP che ha lanciato l'applicazione console restituisce il file binario byte per byte come risposta alla richiesta ricevuta. L'applicazione della console può essere scritta in qualsiasi linguaggio di programmazione che gira 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 stampare l'output di quel comando della console sull'output HTML per trovare la versione esatta del software del server. Quindi installare la stessa identica versione del software in un'istanza VirtualBox, compilare/assemblare qualsiasi binario completamente autonomo, preferibilmente statico, che si desidera e quindi caricarli sul server. Da quel momento in poi l'applicazione PHP può usare quei binari nel ruolo dell'applicazione console che ha il multi-thread corretto. È una soluzione sporca, inaffidabile, a una situazione, quando l'amministratore del server non ha installato tutte le necessarie implementazioni del linguaggio di programmazione sul server. La cosa a cui prestare attenzione è che ad ogni richiesta che l'applicazione PHP riceve le applicazioni della console termina/esce/get_killed.

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

0
Martin Vahi