Maison  >  Article  >  développement back-end  >  Comment implémenter le multi-threading en PHP

Comment implémenter le multi-threading en PHP

墨辰丷
墨辰丷original
2018-06-01 09:27:535061parcourir

Le multi-threading est une très bonne chose en Java. De nombreux amis disent que le multi-threading PHP ne peut pas être utilisé en PHP. En fait, c'est une fausse déclaration. Cet article présente deux méthodes d'implémentation du multi-threading en PHP. Si vous êtes intéressé, les étudiants peuvent y jeter un œil.

PHP lui-même prend-il en charge le multi-threading ? Cependant, nous pouvons utiliser d'autres méthodes pour réaliser le multi-threading, telles que les services shell, tels que les serveurs Web. Dans cet article, nous expliquerons comment implémenter ces deux éléments. méthodes. Les amis dans le besoin peuvent venir s'y référer.

Le multi-threading est une très bonne chose en Java. De nombreux amis disent que le multi-threading PHP ne peut pas être utilisé en PHP. En fait, c'est une fausse déclaration. est lié à la fonction fsockopen. Ci-dessous, nous présenterons le code spécifique du programme d'implémentation. Les étudiants qui ont besoin d'en savoir plus peuvent s'y référer.

Lorsque quelqu'un souhaite implémenter des fonctions de concurrence, il pense généralement à utiliser des threads fork ou spawn, mais lorsqu'il découvre que PHP ne prend pas en charge le multi-threading, il peut changer d'avis et utiliser quelque chose qui est pas assez bon langage, comme Perl.

En fait, dans la plupart des cas, vous n'avez pas besoin d'utiliser fork ou thread, et vous obtiendrez de meilleures performances que d'utiliser fork ou thread.

Supposons que vous souhaitiez créer un service pour vérifier n serveurs en cours d'exécution afin de vous assurer qu'ils fonctionnent toujours normalement. Vous pourriez écrire du code comme ceci :

Code comme ceci :

<?php
$hosts = array("host1.sample.com", "host2.sample.com", "host3.sample.com");
$timeout = 15;
$status = array();
foreach ($hosts as $host) {
$errno = 0;
 $errstr = "";
 $s = fsockopen($host, 80, $errno, $errstr, $timeout);
 if ($s) {
 $status[$host] = "Connectedn";
 fwrite($s, "HEAD / HTTP/1.0rnHost: $hostrnrn");
 do {
 $data = fread($s, 8192);
 if (strlen($data) == 0) {
 break;
 }
 $status[$host] .= $data;
 } while (true);
 fclose($s);
 } else {
 $status[$host] = "Connection failed: $errno $errstrn";
 }
}
print_r($status);
?>

Cela fonctionne bien, mais étendre ce code pour gérer un grand nombre de serveurs prendrait beaucoup de temps jusqu'à ce que fsockopen() ait analysé le nom d'hôte et établi une connexion réussie (ou retardé $timeout secondes).

Nous devons donc abandonner ce code ; nous pouvons établir une connexion asynchrone - pas besoin d'attendre que fsockopen renvoie l'état de la connexion. PHP doit encore résoudre le nom d'hôte (il est donc plus judicieux d'utiliser l'adresse IP directement), mais il reviendra immédiatement après l'ouverture d'une connexion, et nous pourrons alors nous connecter au serveur suivant.

Il existe deux façons d'y parvenir ; en PHP5, vous pouvez utiliser la nouvelle fonction stream_socket_client() pour remplacer directement fsocketopen(). Pour les versions antérieures à PHP5, vous devez le faire vous-même et utiliser l'extension sockets pour résoudre le problème.

Voici la solution en PHP5 :

Il fonctionne bien, mais après que fsockopen() analyse le nom d'hôte et en construit un avec succès Mise à l'échelle de ce code gérer un grand nombre de serveurs prendrait beaucoup de temps avant de se connecter (ou retarderait $timeout secondes).

Nous devons donc abandonner ce code ; nous pouvons établir une connexion asynchrone - pas besoin d'attendre que fsockopen renvoie l'état de la connexion. PHP doit encore résoudre le nom d'hôte (il est donc plus judicieux d'utiliser l'adresse IP directement), mais il reviendra immédiatement après l'ouverture d'une connexion, et nous pourrons alors nous connecter au serveur suivant.

Il existe deux façons d'y parvenir ; en PHP5, vous pouvez utiliser la nouvelle fonction stream_socket_client() pour remplacer directement fsocketopen(). Pour les versions antérieures à PHP5, vous devez le faire vous-même et utiliser l'extension sockets pour résoudre le problème.

Le code est le suivant :

<?php
$hosts = array("host1.sample.com", "host2.sample.com", "host3.sample.com");
$timeout = 15;
$status = array();
$sockets = array();
/* Initiate connections to all the hosts simultaneously */
foreach ($hosts as $id => $host) {
 $s = stream_socket_client("
$
$host:80", $errno, $errstr, $timeout,
 STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT);
 if ($s) {
 $sockets[$id] = $s;
 $status[$id] = "in progress";
 } else {
 $status[$id] = "failed, $errno $errstr";
 }
}
/* Now, wait for the results to come back in */
while (count($sockets)) {
 $read = $write = $sockets;
 /* This is the magic function - explained below */
 $n = stream_select($read, $write, $e = null, $timeout);
 if ($n > 0) {
 /* readable sockets either have data for us, or are failed
 * connection attempts */
 foreach ($read as $r) {
  $id = array_search($r, $sockets);
  $data = fread($r, 8192);
  if (strlen($data) == 0) {
 if ($status[$id] == "in progress") {
 $status[$id] = "failed to connect";
 }
 fclose($r);
 unset($sockets[$id]);
  } else {
 $status[$id] .= $data;
  }
 }
 /* writeable sockets can accept an HTTP request */
 foreach ($write as $w) {
 $id = array_search($w, $sockets);
 fwrite($w, "HEAD / HTTP/1.0rnHost: "
 . $hosts[$id] . "rnrn");
 $status[$id] = "waiting for response";
 }
 } else {
 /* timed out waiting; assume that all hosts associated
 * with $sockets are faulty */
 foreach ($sockets as $id => $s) {
 $status[$id] = "timed out " . $status[$id];
 }
 break;
 }
}
foreach ($hosts as $id => $host) {
 echo "Host: $hostn";
 echo "Status: " . $status[$id] . "nn";
} 
?>

Nous utilisons stream_select() pour attendre que les sockets ouvrent l'événement de connexion. stream_select() appelle la fonction select(2) du système pour fonctionner : les trois premiers paramètres sont les tableaux de flux que vous souhaitez utiliser ; vous pouvez les lire, écrire et obtenir des exceptions (pour les trois paramètres respectivement). stream_select() peut attendre qu'un événement se produise en définissant le paramètre $timeout (secondes) - lorsque l'événement se produit, les données du socket correspondantes seront écrites dans les paramètres que vous avez transmis.

Ce qui suit est l'implémentation des versions après PHP 4.1.0. Si vous avez inclus le support des sockets (ext/sockets) lors de la compilation de PHP, vous pouvez utiliser un code similaire à celui ci-dessus, il vous suffit de modifier le fichier. ci-dessus Les fonctions des fonctions streams/système de fichiers sont implémentées à l'aide des fonctions ext/sockets. La principale différence est que nous utilisons la fonction suivante au lieu de stream_socket_client() pour établir la connexion :

Le code est le suivant :

<?php
// This value is correct for Linux, other systems have other values
define(&#39;EINPROGRESS&#39;, 115);
function non_blocking_connect($host, $port, &$errno, &$errstr, $timeout) {
 $ip = gethostbyname($host);
 $s = socket_create(AF_INET, SOCK_STREAM, 0);
 if (socket_set_nonblock($s)) {
 $r = @socket_connect($s, $ip, $port);
 if ($r || socket_last_error() == EINPROGRESS) {
 $errno = EINPROGRESS;
 return $s;
 }
 }
 $errno = socket_last_error($s);
 $errstr = socket_strerror($errno);
 socket_close($s);
 return false;
}
?>

Remplacez maintenant stream_select() par socket_select(), fread() par socket_read(), fwrite() par socket_write() et fclose() par socket_close(). Le script peut être exécuté !

L'avancée de PHP5 est que vous pouvez utiliser stream_select() pour traiter presque tous les flux - par exemple, vous pouvez l'utiliser pour recevoir une entrée au clavier via include STDIN et l'enregistrer dans un tableau, et vous peut également le recevoir via les données proc_open () dans le tube ouvert.

Partageons une classe PHP multi-thread

Le code est le suivant :

class thread {
 
 var $hooks = array();
 var $args = array();
 
 function thread() {
 }
 
 function addthread($func)
 {
  $args = array_slice(func_get_args(), 1);
  $this->hooks[] = $func;
  $this->args[] = $args;
  return true;
 }
 
 function runthread()
 {
  if(isset($_GET[&#39;flag&#39;]))
  {
   $flag = intval($_GET[&#39;flag&#39;]);
  }
  if($flag || $flag === 0)
  {
   call_user_func_array($this->hooks[$flag], $this->args[$flag]);
  }
  else
  {
   for($i = 0, $size = count($this->hooks); $i < $size; $i++)
   {
    $fp=fsockopen($_SERVER[&#39;HTTP_HOST&#39;],$_SERVER[&#39;SERVER_PORT&#39;]);
    if($fp)
    {
     $out = "GET {$_SERVER[&#39;PHP_SELF&#39;]}?flag=$i HTTP/1.1rn";
     $out .= "Host: {$_SERVER[&#39;HTTP_HOST&#39;]}rn";
     $out .= "Connection: Closernrn";
     fputs($fp,$out);
     fclose($fp);
    }
   }
  }
 }
}

Résumé : Ce qui précède représente l'intégralité du contenu de cet article, j'espère qu'il sera utile à l'étude de chacun.

Recommandations associées :

phpPaiement d'entreprise via paiement WeChat

php Analyse des cas de verrouillage simultanés

phpExplication détaillée des exemples d'algorithmes de tri

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn