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?
Sì, puoi fare multi-threading in PHP con pthreads
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);
}
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]);
}
}
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]
$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"];
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);
}
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
session_start();
var_dump($_SESSION);
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
session_start();
$_SESSION["closesession"] = true;
var_dump($_SESSION);
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.
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
l'utilizzo dei thread è reso possibile dall'estensione PECL pthreads
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.
È 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.
Che ne dici di pcntl_fork?
controlla la nostra pagina di manuale per esempi: PHP pcntl_fork
A seconda di ciò che stai cercando di fare, potresti anche usare curl_multi per realizzarlo.
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).
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.
Puoi avere l'opzione di:
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.