WEB-d Développement Web

PHP, SQL, HTML5, CSS3, Javascript, Mootools, Référencement, SEO, CMS, e-commerce, Apache, Linux, Ubuntu, ...

PHP et les threads

PHP, via l'extension pthreads, permet de créer et d'utiliser des threads POSIX.

Pré-requis

Pour installer cette extension, PHP doit être configuré avec l'option ZTS activée ( --enable-maintainer-zts). Ce n'est généralement pas le cas de la version fournie avec les distributions standard. Vous devrez donc compiler vous-même PHP. Voir à ce propos l'article traitant de la compilation de PHP5.4 sur Ubuntu 12.04.

Installation

Vous pourrez ensuite installer l'extension pthreads via PECL:


sudo /opt/php-5.4/bin/pecl install "channel://pecl.php.net/pthreads-0.0.44"

Il faut maintenant ajouter l'extension à la configuration de PHP. Vous pouvez soit le faire directement dans le fichier php.ini, soit créer un fichier conf.d/pthreads.ini séparé:


extension=pthreads.so

Utilisation

Pour créer des threads, il suffit de créer une classe étendant la classe Thread, et implémenter la méthode run():


class My_Thread extends Thread
{

  public function run() {
    echo "Thread running...\n";
    // Faire quelque-chose de lent...
  }

}

$t = new My_Thread();
$t->start();

// Cette portion du code est exécutée en parallèle avec le Thread t
 

Dans un cas réel, on pourrait par exemple utiliser des threads pour télécharger des données sur le réseau, ou pour traiter des images ou des fichiers:


class Async_Process extends Thread
{
  $file = "";

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

  public function run() {
    // Traiter l'image ou le fichier...
  }

}

$images = array("img01.jpg", "img02.jpg", "img03.jpg");
$threads = array();

foreach ($images as $image) {
  $t = new Async_Process($image);
  $t->start();
  $threads[] = $t;
}


// Attendre que tous les threads aient fini:
foreach ($threads as $t) {
  $t->join();
}
 

Gestion de la mémoire

Contrairement à Java, en PHP l'espace mémoire des différents threads est protégé: un thread peut lire, mais ne peut pas écrire dans l'espace mémoire d'un autre thread. Voici un exemple de code:


class Counter
{
  protected $value = 1;

  public function inc() {
    echo $this->value . ",";
    $this->value = $this->value + 1;
    echo $this->value . ",";
  }
}

class My_Thread extends Thread
{
  protected $counter;

  public function __construct(Counter $c) {
    $this->counter = $c;
  }

  public function run() {
    echo "Thread running...\n";
    for ($i=0; $i<10; $i++) {
      $this->counter->inc();
    }
  }

}

$c = new Counter();

$t1 = new My_Thread($c);
$t1->start();

sleep(1);
 

En Java, on s'attendrait à ce que le résultat affiche 1,2,2,3,3,4,4,5,5,... Dans ce cas-ci, le résultat affiché est "1,2,1,2,1,2,...". Le Counter ($c) est créé par le thread principal. A chaque appel de la méthode inc() par le thread t1, value est incrémenté, mais la nouvelle valeur (2) ne peut pas être écrite en mémoire par t1, car Counter se trouve dans la zone mémoire du thread principal. A l'itération suivante counter a donc toujours la même valeur: 1, et ainsi de suite...

De la même façon, à la fin du script ci-dessous, la valeur de $counter est toujours 0:


$counter = 0;

function inc() {
  global $counter;
  $counter++;
}

class My_Thread extends Thread
{
  public function run() {
    echo "Thread running...\n";
    for ($i=0; $i<10; $i++) {
      inc();
    }
  }

}

$t1 = new My_Thread();
$t1->start();

sleep(1);

echo $counter;
 

La solution pour partager des variables entre threads est d'utiliser la class Stackable...

Articles similaires