ホームページ  >  記事  >  php教程  >  PHPがマルチスレッドを実装できない問題を賢く解決

PHPがマルチスレッドを実装できない問題を賢く解決

WBOY
WBOYオリジナル
2016-06-21 08:51:02904ブラウズ

PHPでマルチスレッドを実装する方法はありますか?複数のサーバーに基づいて PHP アプリケーションを作成しているとします。理想的には、リクエストを次々に送信するのではなく、同時に複数のサーバーに送信します。出来ますか?同時実行機能を実装したい場合、通常はフォークまたは生成スレッドの使用を考えますが、PHP がマルチスレッドをサポートしていないことがわかると、考えを変え、Perl などの十分ではない言語を使用する可能性があります。

実際、ほとんどの場合、フォークやスレッドを使用する必要はなく、フォークやスレッドを使用するよりもパフォーマンスが向上します。 n 台の実行中のサーバーが正しく機能していることを確認するサービスを構築するとします。次のようなコードを書くとよいでしょう:


  1. 		$hosts = array("host1.sample.com", "host2.sample.com", "host3.sample.com");  
  2. $タイムアウト = 15;
  3. $status = array();
  4. foreach ($hosts として $host) {
  5. $errno = 0;
  6. $errstr = "";
  7. $s = fsockopen($host, 80, $errno, $errstr, $timeout);
  8. if ($s)
  9. $status[$host] = "接続済み";
  10. fwrite($s, "HEAD / HTTP/1.0rnHost: $hostrnrn");
  11. する {
  12. $data = fread($s, 8192);
  13. If (strlen($data) == 0) {
  14. 休憩
  15.                                                                                                     
  16. $status[$host] .= $data;
  17.                                                                                           
  18. fclose($s);
  19.                                                                                                
  20. それ以外 {
  21. $status[$host] = "接続に失敗しました: $errno $errstrn";
  22.                                                                                               
  23. }
  24. print_r($ステータス);
  25. ?>
  26. これは問題なく動作しますが、このコードを拡張して多数のサーバーを管理するには、 fsockopen() がホスト名を解析して正常な接続を確立するまで (または $timeout 秒の遅れが生じるまで) 長い時間がかかります。
  27. したがって、このコードを放棄する必要があります。fsockopen が接続ステータスを返すのを待つ必要がなく、非同期接続を確立できます。 PHP は依然としてホスト名を解決する必要があります (したがって、IP を直接使用する方が賢明です) が、接続を開いた後すぐにホスト名が返されるため、次のサーバーに接続できます。
  28. これを実現するには 2 つの方法があります。PHP5 では、新しい stream_socket_client() 関数を使用して fsocketopen() を直接置き換えることができます。 PHP5 より前のバージョンの場合、問題を解決するには自分で実行し、ソケット拡張機能を使用する必要があります。 PHP5 での解決策は次のとおりです:
  29. 
    
    1. 		$hosts = array("host1.sample.com", "host2.sample.com", "host3.sample.com");  
    2. $timeout = 15;  
    3. $status = array();  
    4. $sockets = array();  
    5. /* すべてのホストへの接続を同時に開始します */
    6. foreach ($hosts as $id => $host) {
    7.         $s = stream_socket_client("$host:80", $errno, $errstr, $timeout,
    8.              STREAM_CLIENT_ASYNC_CONNECTSTREAM_CLIENT_CONNECT);   
    9.         if ($s) {
    10.             $sockets[$id] = $s;    
    11.             $status[$id] = 「進行中」;   
    12.         }
    13.         else { $status[$id] = 「失敗、$errno $errstr」;   
    14.         }
    15. }
    16. /* さて、結果が 戻ってくるまで待ちます */
    17.  
    18. while (count($sockets)) {
    19.       $read = $write = $ソケット;   
    20. /* これは 魔法の 機能です - 以下で説明します */
    21.       $n = stream_select($read, $write, $e = null, $timeout);   
    22.       if ($n > 0) {
    23.       /* 読み取り可能なソケットには、データが含まれているか、失敗しました。 * 接続試行*/
    24.           foreach ($read as $r) {
    25.                    $id = array_search($r, $sockets);        
    26.                    $data = fread($r, 8192);        
    27.           if (strlen($data) == 0) {
    28.                    if ($status[$id] == "進行中") {
    29.                        $status[$id] = 「接続に失敗しました」;     
    30.                    }
    31.           fclose($r);     
    32.           unset($sockets[$id]);        
    33.            }
    34.            他 {
    35.                  $status[$id] .= $data;        
    36.            }
    37.         }    
    38. /* 書き込み可能なソケットは HTTP リクエストを受け入れることができます */
    39. foreach ($write as $w) {
    40.          $id = array_search($w, $sockets);     
    41.          fwrite($w, "HEAD / HTTP/1.0rnHost: "
    42.          。 $hosts[$id] 。  "rnrn");     
    43.          $status[$id] = 「応答を待っています」;    
    44.          }
    45. }
    46. 他 {
    47. /* 待機中にタイムアウトになりました。 $sockets に関連付けられたすべてのホストに障害があると仮定します。*/
    48. foreach ($sockets as $id => $s) {
    49.          $status[$id] = 「タイムアウト 」
    50.          。 $ステータス[$id];    
    51.          }
    52. 壊す;   
    53.   }
    54. }
    55. foreach ($hosts as $id => $host) {
    56.       echo "ホスト: $hostn"; echo 「ステータス: 」
    57.       。 $status[$id] 。 「ん」;  
    58. }
    59. ?> 

    stream_select() は、システムの select(2) 関数を使用して、ソケットがオープンされるのを待ちます。 上の 3 つのパラメータは、使用されるストリームの数です。

    以下は PHP4.1.0 以降のバージョンです。PHP のバージョンにソケット (ext/sockets) が含まれている場合、上にあるストリーム/ファイル システム関数の機能を拡張する必要がある場合のみ、上にあるものと同様のコードを使用できます。 /sockets 関数が実行されます。主な違いは、stream_socket_client() の代わりに次の関数を使用して接続を確立することです:

    
    
    1. 		// This value is correct for Linux, other systems have other values  
    2. define('EINPROGRESS', 115);  
    3. function non_blocking_connect($host, $port, &$errno, &$errstr, $timeout) {   
    4.         $ip = gethostbyname($host);   
    5.         $s = socket_create(AF_INET, SOCK_STREAM, 0);   
    6.         if (socket_set_nonblock($s)) {    
    7.            $r = @socket_connect($s, $ip, $port);    
    8.            if ($r  socket_last_error() == EINPROGRESS) {     
    9.                   $errno = EINPROGRESS;     
    10.                   return $s;    
    11.                }   
    12.          }   
    13.         $errno = socket_last_error($s);   
    14.         $errstr = socket_strerror($errno);   
    15.         socket_close($s);   
    16.         return false;  
    17. }  
    18. ?> 

    现在用socket_select()替换掉stream_select(),用socket_read()替换掉fread(),用socket_write()替换掉fwrite(),用socket_close()替换掉fclose()就可以执行脚本了! PHP5的先进之处在于,你可以用stream_select()处理几乎所有的stream。例如你可以通过include STDIN用它接收键盘输入并保存进数组,你还可以接收通过proc_open()打开的管道中的数据。



声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。