Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Erläuterung der PHP-Multithreading-Implementierungsmethoden und Anwendungsbeispiele

Detaillierte Erläuterung der PHP-Multithreading-Implementierungsmethoden und Anwendungsbeispiele

高洛峰
高洛峰Original
2016-12-21 13:08:55919Durchsuche

Jetzt stellen wir den spezifischen PHP-Multithread-Implementierungsprogrammcode vor. Schüler, die mehr wissen müssen, können darauf zurückgreifen.
Wenn jemand Parallelitätsfunktionen implementieren möchte, denkt er normalerweise an die Verwendung von Fork- oder Spawn-Threads. Wenn er jedoch feststellt, dass PHP kein Multithreading unterstützt, ändert er möglicherweise seine Meinung und verwendet einige nicht gut genug Sprachen, wie z. B. Perl .
Tatsächlich müssen Sie in den meisten Fällen weder Fork noch Thread verwenden und erzielen eine bessere Leistung als mit Fork oder Thread.
Angenommen, Sie möchten einen Dienst erstellen, um n laufende Server zu überprüfen, um sicherzustellen, dass sie noch normal funktionieren. Sie könnten Code wie den folgenden schreiben:
Der Code lautet wie folgt

<?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);
?>

Er läuft sehr gut, aber nachdem fsockopen() den Hostnamen analysiert und eine erfolgreiche Verbindung hergestellt hat (oder $timeout Sekunden verzögert) Bisher hätte die Skalierung dieses Codes zur Verwaltung einer großen Anzahl von Servern viel Zeit in Anspruch genommen.
Wir müssen diesen Code also aufgeben; wir können eine asynchrone Verbindung herstellen – wir müssen nicht warten, bis fsockopen den Verbindungsstatus zurückgibt. PHP muss den Hostnamen noch auflösen (daher ist es sinnvoller, die IP direkt zu verwenden), aber er kehrt sofort nach dem Öffnen einer Verbindung zurück und wir können uns dann mit dem nächsten Server verbinden.
Es gibt zwei Möglichkeiten, dies zu erreichen: In PHP5 können Sie die neue Funktion stream_socket_client() verwenden, um fsocketopen() direkt zu ersetzen. Bei Versionen vor PHP5 müssen Sie es selbst tun und die Sockets-Erweiterung verwenden, um das Problem zu lösen.
Das Folgende ist die Lösung in PHP5:
Der Code lautet wie folgt

<?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";
} 
?>

Wir verwenden stream_select(), um auf das Verbindungsereignis des Öffnens von Sockets zu warten. stream_select() ruft die Funktion select(2) des Systems auf, um zu funktionieren: Die ersten drei Parameter sind die Arrays von Streams, die Sie verwenden möchten, Sie können sie lesen, schreiben und Ausnahmen erhalten (jeweils für die drei Parameter). stream_select() kann auf das Eintreten eines Ereignisses warten, indem der Parameter $timeout (Sekunden) festgelegt wird. Wenn das Ereignis eintritt, werden die entsprechenden Socket-Daten in die von Ihnen übergebenen Parameter geschrieben.
Das Folgende ist die Implementierung von PHP 4.1.0 und höher. Wenn Sie beim Kompilieren von PHP Sockets (ext/sockets)-Unterstützung integriert haben, können Sie ähnlichen Code wie oben verwenden, müssen jedoch die Funktionen der Streams/ hinzufügen. Dateisystemfunktion oben. Implementiert mit der ext/sockets-Funktion. Der Hauptunterschied besteht darin, dass wir anstelle von stream_socket_client() die folgende Funktion verwenden, um die Verbindung herzustellen:
Der Code lautet wie folgt

<?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;
}
?>

Ersetzen Sie nun stream_select() durch socket_select() und fread() durch socket_read() ), ersetzen Sie fwrite() durch socket_write(), ersetzen Sie fclose() durch socket_close() und schon können Sie das Skript ausführen!
Der Fortschritt von PHP5 besteht darin, dass Sie stream_select() verwenden können, um fast alle Streams zu verarbeiten. Sie können damit beispielsweise Tastatureingaben empfangen, indem Sie STDIN einbinden und in einem Array speichern, und Sie können sie auch von einem empfangen Pipe wird durch proc_open()-Daten geöffnet.
Lassen Sie uns eine PHP-Multithread-Klasse teilen
Der Code lautet wie folgt

* @title:   PHP多线程类(Thread)
 * @version:  1.0
 * 
 * PHP多线程应用示例:
 * require_once &#39;thread.class.php&#39;;
 * $thread = new thread();
 * $thread->addthread(&#39;action_log&#39;,&#39;a&#39;);
 * $thread->addthread(&#39;action_log&#39;,&#39;b&#39;);
 * $thread->addthread(&#39;action_log&#39;,&#39;c&#39;);
 * $thread->runthread();
 * 
 * function action_log($info) {
 *   $log = &#39;log/&#39; . microtime() . &#39;.log&#39;;
 *   $txt = $info . "rnrn" . &#39;Set in &#39; . Date(&#39;h:i:s&#39;, time()) . (double)microtime() . "rn";
 *   $fp = fopen($log, &#39;w&#39;);
 *   fwrite($fp, $txt);
 *   fclose($fp);
 * }
 */
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);
        }
      }
    }
  }
}

Ich hoffe, dass dieser Artikel für das PHP-Programmierdesign aller hilfreich sein wird.

Ausführlichere Erläuterungen zu PHP-Multithreading-Implementierungsmethoden und Anwendungsbeispiele finden Sie auf der chinesischen PHP-Website!


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn