15
mag
08

PHP Multithreading

Immagino che ai più le due parole del titolo suonino abbastanza male, in effetti php per sua natura non supporta i thread, il che è palesemente ovvio visto che è un linguaggio di scripting nato per fare tutt’altra cosa.

Avviene però che in certi casi, se per esempio avete fatto un algoritmo in php ma vi accorgete che avreste bisogno dei thread e non avete voglia di mettervi a riscrivere tutto, è proprio necessario un modo per implementarsi i thread.

Allora potremmo usare l’operazione asincrona più naturale che il linguaggio ci fornisce, una richiesta asincrona a una pagina web.

Iniziamo subito con il codice della libreria Thread.php:

<?
class Thread{
    var $func;
    var $arg;
    var $thisFileName;
    var $fp;
    var $host;
    var $port;
    function Thread($host,$port=""){
        $this->host = $host;
        if ($port != ""){
            $this->port = $port;
        }else{
            $this->port = 80;
        }
        $this->thisFileName = $_SERVER["SCRIPT_NAME"];
    }
    function setFunc($func,$arg=false){
        $i=0;
        $this->arg = "";
        if ($arg){
            foreach ($arg as $argument){
                $this->arg .= "&a[]=".urlencode($argument);
            }
        }
        $this->func = $func;
    }
    function setPort($port){
        $this->port = $port;
    }
    function setHost($host){
        $this->host = $host;
    }
    function start(){
        $this->fp = fsockopen($this->host,$this->port);
        $header = "GET ".$this->thisFileName."?threadrun=1&f=".urlencode($this->func).$this->arg." HTTP/1.1\r\n";
        $header .= "Host: ".$this->host."\r\n";
        $header .= "Connection: Close\r\n\r\n";
        fputs($this->fp,$header);
    }
    function getreturn(){
        $flag=false;
        while (!feof($this->fp)) {
            $buffer = fgets($this->fp, 4096);
            if ($flag){
                $output .= $buffer;
            }
            if (trim($buffer) == ""){
                $flag = true;
            }
        }
        return unserialize(trim($output));
    }
}
if (isset($_GET['threadrun'])){
    $arg_str = "";
    $i=0;
    if (isset($_GET['a'])){
        foreach($_GET['a'] as $argument){
            if ($i == 0){
                $arg_str .= '"'.urldecode($argument).'"';
            }else{
                $arg_str .= ",".'"'.urldecode($argument).'"';
            }
            $i++;
        }

    }
    eval("\$return = ".$_GET['f']."(".$arg_str.");");
    echo serialize($return);
    exit;
}

?>

Questa libreria è stata scritta originariamente da Alex Lau, io ho fatto alcune modifiche che saranno illustrate dopo.

Ora il codice di esempio per capire come funziona (main.php):

<?php
include_once("Thread.php");
function get($num)
{
	$out = file_get_contents("http://localhost:8080/tesi/crawling/worker.php?num=".urlencode($num));
	return time()." ".$out;
}

for ($p=0; $p<6; $p++) {
		$thread[$p] = new Thread("localhost",8080);
		$thread[$p]->setFunc("get",array($p));
		$thread[$p]->start();
    }

for ($p=0; $p<6; $p++) {
	echo $thread[$p]->getreturn()."<br/>";
}
?>

E di worker.php:

<?
	sleep(5-$_GET['num']);
	echo "thread ".$_GET['num'];
?>

L’ovvio risultato è quello di mostrare come il primo thread creato è anche l’ultimo a ritornare ovvero ha il timestamp più alto.

Nello script di esempio vediamo come si usa la classe Thread, intanto includiamo il file, poi definiamo una funzione che richiama un’altro script passandogli un parametro, questo script contiene ovviamente il codice che vorremmo rendere asicrono.

Andiamo ora a creare il thread, ad impostare il nome della funzione e i suoi parametri, è importante notare che i parametri vanno passati dentro un array sia che siano uno solo sia che siano cento.

Dopo di che lanciamo il thread, successivamente andremo a recuperare l’output della richiesta, notare che questa richiesta è bloccante stavolta, quindi la possiamo utilizzare per monitorare i thread.

Ma come funziona la classe?

Tralasciano l’implementazione il modo è molto semplice, al momento della creazione del thread la classe si salva le informazioni sulla funzione e i suoi argomenti, quando poi si fa partire, la pagina richiama se stessa ma aprendo un socket asincrono, la pagina richiamata in modo asicrono esegue ovviamente le operazioni richieste e il suo output è riferito dall’esterno con un puntatore, in pratica i thread sono creati da apache stesso nel modo più ovvio e naturale che si possa pensare.

Vi faccio notare infine che per motivi di protocollo i valori passati come argomento della funzione sono tutti convertiti in stringhe…

Spero vi sia stato utile.

Enjoy!

About these ads

4 Responses to “PHP Multithreading”


  1. 17 maggio 2008 alle 2:17:13

    Oggi ho aggiunto anche la funzione isalive per verificare se il thread ha terminato, in modo non bloccante, però non ho pubblicato la cosa perché con jiimbo ci siamo ripromessi di lavorare sulla libreria per renderla più completa e magari aggiungere anche un monitor o qualcosa simile al pool di thread….

  2. 3 pos
    19 gennaio 2011 alle 12:24:57

    Non ha senso! e’ un fake. Studia sei ancora lontano dall’arrivo.

  3. 4 Bruno
    30 settembre 2011 alle 23:08:21

    la porta 8080 è obbligatoria ai fini del funzionamento?


Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...


Difendi Rebeldia!

Aggiungi ai tuoi feed

 RSS Feed
Add to Google
Add to My Yahoo!
Add to Technorati Favorites!
Add to netvibes

Blog Stats

  • 239,559 hits

Pidduisti on-line

hit counters


Made on a Mac
Last.fm
Giveaway of the Day
highlightInterests("ProfileMusica");
Musicatable.lfmWidget8f0839bdbf919d97305135788e54986d td {margin:0 !important;padding:0 !important;border:0 !important;}table.lfmWidget8f0839bdbf919d97305135788e54986d tr.lfmHead a:hover {background:url(http://cdn.last.fm/widgets/images/en/header/chart/weeklytracks_regular_blue.png) no-repeat 0 0 !important;}table.lfmWidget8f0839bdbf919d97305135788e54986d tr.lfmEmbed object {float:left;}table.lfmWidget8f0839bdbf919d97305135788e54986d tr.lfmFoot td.lfmConfig a:hover {background:url(http://cdn.last.fm/widgets/images/en/footer/blue.png) no-repeat 0px 0 !important;;}table.lfmWidget8f0839bdbf919d97305135788e54986d tr.lfmFoot td.lfmView a:hover {background:url(http://cdn.last.fm/widgets/images/en/footer/blue.png) no-repeat -85px 0 !important;}table.lfmWidget8f0839bdbf919d97305135788e54986d tr.lfmFoot td.lfmPopup a:hover {background:url(http://cdn.last.fm/widgets/images/en/footer/blue.png) no-repeat -159px 0 !important;}

pages

maggio: 2008
L M M G V S D
« apr   giu »
 1234
567891011
12131415161718
19202122232425
262728293031  

Iscriviti

Ricevi al tuo indirizzo email tutti i nuovi post del sito.

%d blogger cliccano Mi Piace per questo: