ホームページ  >  記事  >  バックエンド開発  >  PHP_PHP チュートリアルにおける (疑似) マルチスレッドとマルチプロセッシングの詳細な分析

PHP_PHP チュートリアルにおける (疑似) マルチスレッドとマルチプロセッシングの詳細な分析

WBOY
WBOYオリジナル
2016-07-21 15:01:45782ブラウズ

(擬似)マルチスレッド:外部の力
の助けを借りて、WEBサーバー自体のマルチスレッドを利用して処理し、マルチスレッドの実装に必要なプログラムをWEBから複数回呼び出します。サーバ。
引用:
PHP自体はマルチスレッドをサポートしていないことはわかっていますが、Webサーバーはマルチスレッドをサポートしています。
つまり、複数の人が同時にアクセスできるようにするのが私がマルチスレッドを実装する方法です。 PHP の基本の -threading。
今、ファイル a.php を実行しているとします。しかし、プログラム内で別の b.php を実行するように WEB サーバーにリクエストします。すると、2 つのファイルが同時に実行されます。

(PS) : リンクリクエスト 送信後、クライアントが終了したかどうかに関係なく、WEB サーバーはそれを実行します)
場合によっては、実行したいのが別のファイルではなく、このファイル内のコードの一部である場合があります。 ?
実際、パラメータを使用して a.php が実行するプログラムを制御できます。

例を見てみましょう:

コードをコピーします コードは次のとおりです:
function runThread(){
$fp = fsockopen( 'localhost', 80, $errno, $errmsg);
fputs($fp, "GET /a.php?act=brnrn");//第二引数これは HTTP プロトコルで指定されているリクエストヘッダーです。理解している場合は、RFC の定義を参照してください
fclose ($ fp)
}
Function a () {
$ fp = fopen ('Result_a.log', ' w');
fputs ($ fp, 'set in' . Date('h:i:s', time()) . (double)microtime() . "rn");
fclose($fp); }
function b(){
$fp = fopen(' result_b.log', 'w');
fputs($fp, 'Set in ' . Date('h:i:s', time()) . (double)microtime() . "rn");
fclose ($fp);
}
if(!isset($_GET['act'])){ $_GET['act'] = 'a';} ;
if($_GET['act'] == ' a'){
runThread();
a();
}else if($_GET['act'] == 'b'){
b( );
};
?>


result_a.log と result_b.log を開いて、2 つのファイルのアクセス時間を比較すると、これら 2 つは実際に異なるスレッドで実行されていることがわかります。
上記は単なる例です。
PHP もマルチスレッド化できるようになったので、同期の問題が発生しました。そのため、同期のようなものはありません。 Java メソッドでは、どうすればよいでしょうか。 1. 競合を避けるために同じリソースにアクセスしないようにしてください。ただし、データベースは同時操作をサポートしているため、マルチスレッド PHP では同じファイルにデータを書き込まないでください。書き込む必要がある場合は、同期に他のメソッドを使用します。たとえば、flock を呼び出してファイルをロックし、ファイルが別のスレッドで消えるのを待ちます。この一時ファイルが存在するということは、スレッドが実際に動作していることを意味します。ファイルが存在しない場合は、他のスレッドがそのファイルを解放したことを意味します。

2. fputs の実行後に runThread が取得するソケットからデータを読み取らないようにします。これは、マルチスレッドを実現するために、ノンブロッキング モードを使用する必要があるためです。つまり、fgets のような関数が使用されるとすぐに戻ります。そのため、データの読み取りと書き込みに問題が発生します。ブロッキング モードを使用すると、次のプログラムを実行する前に上記の戻りを待つ必要があるため、データを交換する必要がある場合があります。本当に必要な場合は、socket_set_nonblock($fp) を使用してください。
これには実際的な意味がありますか?いつこのメソッドを使用する必要がありますか?

その答えは次のとおりです。ネットワークリソースを読み取るアプリケーションでは、ネットワークの速度がボトルネックになるため、この方法を採用すると、複数のスレッドで同時に異なるページを読み取ることができます。 8848やsoaso情報番組などのモールサイトから検索できます。アリババのウェブサイトからビジネス情報や企業ディレクトリを読み取るプログラムもあり、この技術も利用されています。 どちらのプログラムも、情報を読み取ってデータベースに保存するためにサーバーに継続的に接続する必要があるためです。 この技術を活用することで、応答待ちのボトルネックを解消します。


複数のプロセス: PHP のプロセス制御関数 (PCNTL/スレッド制御関数) を使用します


は Unix Like OS でのみ使用でき、Windows では使用できません。
PHP をコンパイルするときは、--enable-pcntl を追加する必要があります。WEB サーバー環境ではなく、CLI モードでのみ実行することをお勧めします。

以下は短いテストコードです:
コードをコピーします

コードは次のとおりです:
declare(ticks=1);

$bWaitFlag = FALSE; ///終了するプロセス$intNum = 10; /// プロセスの総数$pids = array(); /// プロセス PID の配列echo ("Startn");for($i = 0; $i < ; $intNum; $i++) {
$pids[ $i] = pcntl_fork();/// 子プロセスを生成し、現在の行からテスト実行コードを開始し、親プロセスのデータ情報を継承しません。
if(!$pids[$i]) {
// 子プロセスのプロセスコードsegment_Start
$str="";
sleep(5+$i);
for ($j=0;$j echo "$i -> " . time() . " $str n";
exit();
// プロセスコードセグメント_End
}
}
if ($bWaitFlag)
{
for($ i = 0; $i < $intNum; $i++) {
pcntl_waitpid($pids[$i], $status, WUNTRACED);
echo "$i を待つ -> ; " . time() . "n";
}
}
echo ("終了");


実行結果例:
CODE:[クリップボードにコピー][qiao@oicq qiao]$ phptest.php
開始
終了
[qiao@oicq qiao]$ ps -aux | grep "php"
qiao 32275 0.0 0.5 49668 6148pts/1 S 14:03 0:00/usr/local/php4/b
qiao 32276 0.0 0.5 49668 6152pts/1 S 14:03 0:00/usr/local/php4 /b
qiao 32277 0.0 0.5 49668 6152pts/1 S 14:03 0:00/usr/local/php4/b
qiao 32278 0.0 0.5 49668 6152pts/1 S 14:03 0:00/usr/local/php4/b
qiao 32279 0.0 0.5 49668 6152pts/1 S 14:03 0:00/usr/local/php4/b
qiao 32280 0.0 0.5 49668 6152pts/1 S 14:03 0:00 /usr/local/php4/b
qiao 32281 0.0 0.5 49668 6152ポイント/1 S 14:03 0:00/usr/local/php4/b
qiao 32282 0.0 0.5 49668 6152ポイント/1 S 14:03 0:00 /usr/local/php4/b
qiao 32283 0.0 0.5 49668 6152ポイント/1 S 14:03 0:00/usr/local/php4/b
qiao 32284 0.0 0.5 49668 6152ポイント/1 S 14:03 0:00/usr/local/php4/b
チャオ 32286 0.0 0.0 1620 600 ポイント/1 S 14:03 0:00 grep php
[qiao@oicq qiao]$ 0 -> 1133503401
1 -> 1133503402 *
2 -> 1133503403 **
3 -> 1133503404 ***
4 -> 1133503405 ****
5 -> 1133503406 *****
6 -> 1133503407 ******
7 -> 1133503408 *******
8 -> 1133503409 ********
9 -> 1133503410 *********
[qiao@oicq qiao]$
如果$bWaitFlag=TURE,则结果如下:
CODE:[クリップボードにコピー][qiao@oicq qiao]$ phptest.php
開始
0 -> 1133503602
0待ち -> 1133503602
1 -> 1133503603 *
お待ちください 1 -> 1133503603
2 -> 1133503604 **
2 待ってください -> 1133503604
3 -> 1133503605 ***
3 待ってください -> 1133503605
4 -> 1133503606 ****
4 待ってください -> 1133503606
5 -> 1133503607 *****
5 待ってください -> 1133503607
6 -> 1133503608 ******
6 までお待ちください -> 1133503608
7 -> 1133503609 *******
7 までお待ちください -> 1133503609
8 -> 1133503610 ********
8 までお待ちください -> 1133503610
9 -> 1133503611 *********
9 までお待ちください -> 1133503611
End
[qiao@oicq qiao]$
多くのプロセスの例を見ると、pcntl_fork() を使用した後、子プロセスを生成し、子プロセスを実行する代コードが、pcntl_fork() の後に始まります。子プロセスは父プロセスのデータ情報を継承しないため (実際には、父プロセスのデータは完全に新しいバックアップを取得します)、そのため子プロセスの実行の制御には if(!$pids[$i]) が使用されます。時間的な関係でのより詳細な研究はまだ行われていませんが、私が提示した手の接続を参照してください。
[文章二] 尝试phpコマンド行脚本多进程并発行実行

除了fork、cli下の并発行方式他有一种,看我的例:
php不多回線程,但我们可以问题转换成「多」 php 内の pcntl_fork は unix プラットフォームのみ使用できるため、ここでは代わりに popen を使用します。

以下は例です。代次如下:

if($argc==1){
echo("argvn");

}$arg = $argv[1];for($i=0; $i< ;10; $i++){ echo($i.".1.".time()." exec $arg n");
if($arg=='php2'){
sleep(1);
echo($i.".2.".time()." exec $arg n");
sleep(1);
}else{
sleep(1);
}
}
?>


主调用者程序、他调用子程程、同時に発行された収集子程序の出力



复制代网

代序如下:

error_reporting(E_ALL);
$handle1 = Popen('php sub.php php1', 'r');
$handle2 = Popen('php sub.php php2', 'r');
$handle3 = Popen ('php sub.php php3', 'r');
echo "'$handle1'; " . gettype($handle1) 。 "n";
echo "'$handle2'; " . gettype($handle2) 。 "n";
echo "'$handle3'; " . gettype($handle3) 。 "n";
//sleep(20);
while(!feof($handle1) || !feof($handle2) || !feof($handle3) )
{
$read = fgets($handle1);
echo $read;
$read = fgets($handle2);
echo $read;
$read = fgets($handle3);
echo $read;
}
pclose($handle1);
pclose($handle2) ;
pclose($handle3);

下は我机上の出力:
C:my_hunter>php exec.php
'リソースID #4'; resource
'リソース ID #5'; resource
'リソース ID #6';リソース
0.1.1147935331 exec php1
0.1.1147935331 exec php2
0.1.1147935331 exec php3
1.1.1147935332 exec php1
0.2.1147935332 exec php2
1.1 .1147935332 exec php3
2.1.1147935333 exec php1
1.1.1147935333 exec php2
2.1.1147935333 exec php3
3.1.1147935334 exec php1
1.2.1147935334 exec php2
3.1.1147935334 exec php3
4.1.1147935335 exec php1
2.1.114 7935335 php2
4.1.1147935335 実行 php3
5.1.1147935336 実行 php1
2.2。 1147935336 exec php2
5.1.1147935336 exec php3
6.1.1147935337 exec php1
3.1.1147935337 exec php2
6.1.1147935337 exec php3
7.1.1147935 338 実行 php1
3.2.1147935338 実行 php2
7.1.1147935338 実行 php3
8.1.1147935339 実行php1
4.1.1147935339 exec php2
8.1.1147935339 exec php3
9.1.1147935340 exec php1
4.2.1147935340 exec php2
9.1.1147935340 exec php3
5 .1.1147935341 exec php2
5.2.1147935342 exec php2
6.1.1147935343 exec php2
6.2.1147935344 exec php2
7.1.1147935345 exec php2
7.2.1147935346 exec php2
8.1.1147935347 exec php2
8.2.1147935348 exec php2
9.1.114 7935349 exec php2
9.2.1147935350 exec php2
**总结:**
** メインプログラム循環等の子プロセスを待機し、fgets または fread によって子プロセスの出力が取得され、時間的に確認されて実行されます。**
----------- ------------------------------------
その後の変更点:
* Popen打开の句柄です単一方向で、子プロセスとのやり取りが必要な場合は、proc_open
* を使用できます。代わりに数組と子関数を使用しますwhile(!feof($handle1)|| !feof($handle2) || !feof($handle3) ) このような厄介な書き込み法
* fread を使用して、毎回ではなく、子プロセスによって生成された出力の取得が完了します。 、里面の実行コマンドを実行し、実行を実行します。同時に存在する子プロセス数を設定できます:

复制番号代番号如下:

/*
メインタスクマネージャー
同時実行サブタスクリスト
*/
include("../common/conf.php");
include("../common/function.php");
/ /開いているプロセスの数
$exec_number = 40;
/***** 主要 ********/
if($argc==1){
echo("argvn");
}
$taskfile = $argv[1] ;
//tasklist
$tasklist = file($taskfile);
$tasklist_len = count($tasklist);
$tasklist_pos = 0;
$handle_list = array();
while(1)
{
//Subプロセスリストが無料の場合、サブプロセスリストに入力します。 /var_dump ($handle_list);
//exit;
}
}
tolog("nn**********************end****** ******* ***********nn", "" , true);



Socketマルチプロセス受信用のコードを添付します:




コードをコピー

コードは次のとおりです:


do {
if (($msgsock =ソケット_accept($sock)) echo "socket_accept() が失敗しました: 理由: " .socket_strerror($msgsock) "n ";
break;
}
$pid = pcntl_fork ();
if ($pid == -1) {
die('フォークできません');
} else if (!$pid) {
... ..
socket_write($msgsock, $msg, strlen ($msg));
do {
......
} while (true);
socket_close($msgsock);
}
} while (true) ;






http://www.bkjia.com/PHPjc/327960.html

www.bkjia.com
tru​​e
http://www.bkjia.com/PHPjc/327960.html技術記事 (擬似)マルチスレッド:外部の力を借りて、WEBサーバー自体のマルチスレッドを利用して処理を行います。マルチスレッドを実現するために必要なプログラムをWEBサーバーから複数回呼び出します。引用: PHP 自体がサポートされていないことはわかっています...




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