スレッドという PECL パッケージを見つけましたが、まだリリースされていません。そして、PHP Web サイトには何も表示されません。
13 に答える
pthreads拡張機能のPHPマニュアルから:
pthreadsは、PHPでユーザーランドのマルチスレッド化を可能にするオブジェクト指向APIです。これには、Webまたはコンソールを対象としたマルチスレッドアプリケーションを作成するために必要なすべてのツールが含まれています。PHPアプリケーションは、スレッド、ワーカー、およびスタッカブルを作成、読み取り、書き込み、実行、および同期できます。
これは信じられないほど信じられないことですが、それは完全に真実です。今日、PHPは、試してみたい人のためにマルチスレッド化できます。
PHP4の最初のリリースである2000年5月22日、PHPにはスレッドセーフアーキテクチャが付属していました。これは、マルチスレッドSAPI(サーバーAPI)環境の個別のスレッドでインタープリターの複数のインスタンスを実行する方法です。過去13年間、このアーキテクチャの設計は維持され、進歩してきました。それ以来、世界最大のWebサイトで本番環境で使用されています。
ユーザーランドでのスレッド化は、PHPチームにとっては決して問題ではなく、今日でもそのようになっています。PHPがビジネスを行っている世界には、ハードウェアを追加するという定義済みのスケーリング方法がすでに存在することを理解する必要があります。長年にわたってPHPが存在し、ハードウェアはますます安くなっているため、これはPHPチームにとってますます懸念事項ではなくなりました。安くなる一方で、はるかに強力になりました。現在、携帯電話とタブレットにはデュアルコアとクアッドコアのアーキテクチャがあり、それに合わせて十分なRAMが搭載されています。デスクトップとサーバーには通常8コアまたは16コア、16ギガバイトと32ギガバイトのRAMが搭載されていますが、常に2つ搭載できるとは限りません。予算内で2台のデスクトップを使用することは、ほとんどの人にとってほとんど役に立ちません。
さらに、PHPはプログラマー以外の人のために書かれたもので、多くの愛好家の母国語です。PHPが非常に簡単に採用される理由は、PHPが習得と記述が容易な言語だからです。今日PHPが非常に信頼できる理由は、PHPの設計に膨大な量の作業が費やされ、PHPグループがすべての決定を下したためです。それは信頼性であり、その素晴らしさは、これらすべての年月を経て、それをスポットライトに保ちます。ライバルが時間やプレッシャーに陥っているところ。
マルチスレッドプログラミングは、ほとんどの場合簡単ではありません。最も一貫性があり信頼性の高いAPIを使用しても、さまざまなことを考える必要があり、多くの誤解があります。PHPグループは、ユーザーランドのマルチスレッドがコア機能になることを望んでいません。真剣に注目されたことは一度もありません。当然のことながらそうです。誰にとっても、PHPは複雑であってはなりません。
すべてを考慮すると、PHPが本番環境に対応し、テスト済みの機能を利用して、私たちが持っているものを最大限に活用できるようにすることで得られるメリットはまだあります。タスクの数は実際には必要ありません。
pthreadsは、それを探求したい人のために、ユーザーがPHPアプリケーションをマルチスレッド化できるようにするAPIを実現します。APIは非常に進行中の作業であり、安定性と完全性のベータレベルを指定しています。
PHPが使用するライブラリの一部はスレッドセーフではないことは周知の事実です。プログラマーには、pthreadがこれを変更できず、試行を試みないことを明確にする必要があります。ただし、インタープリターの他のスレッドセーフ設定と同様に、スレッドセーフなライブラリはすべて使用できます。
pthreadsはPosixスレッドを利用します(Windowsでも)。プログラマーが作成するのは実際の実行スレッドですが、これらのスレッドが役立つためには、PHPを認識している必要があります。ユーザーコードを実行し、変数を共有し、便利な通信手段を提供できます。 (同期)。したがって、すべてのスレッドはインタープリターのインスタンスを使用して作成されますが、設計上、そのインタープリターは、マルチスレッドのサーバーAPI環境と同様に、インタープリターの他のすべてのインスタンスから分離されています。pthreadsは、正気で安全な方法でギャップを埋めようとします。Cのスレッドのプログラマーの懸念の多くは、pthreadのプログラマーにはありません。設計上、pthreadは読み取り時にコピーオンライトと書き込み時にコピーオンライトであるため(RAMは安価です)、2つのインスタンスが同じ物理データを操作することはありません。 、ただし、両方とも別のスレッドのデータに影響を与える可能性があります。
なぜ読み取り時にコピーし、書き込み時にコピーするのか:
public function run() {
...
(1) $this->data = $data;
...
(2) $this->other = someOperation($this->data);
...
}
(3) echo preg_match($pattern, $replace, $thread->data);
(1)pthreadsオブジェクトデータストアで読み取りおよび書き込みロックが保持されている間、データはメモリ内の元の場所からオブジェクトストアにコピーされます。pthreadsは変数のrefcountを調整しません。それ以上の参照がない場合、Zendは元のデータを解放できます。
(2)someOperationへの引数は、オブジェクトストアを参照します。保存された元のデータは、それ自体が(1)の結果のコピーであり、エンジン用にzvalコンテナーに再度コピーされます。これにより、読み取りロックが保持されます。オブジェクトストア、ロックが解除され、エンジンが機能を実行できるようになります。zvalが作成されると、refcountは0になり、操作の完了時にエンジンがコピーを解放できるようになります。これは、zvalへの他の参照が存在しないためです。
(3)preg_matchの最後の引数はデータストアを参照し、読み取りロックが取得され、(1)のデータセットがzvalにコピーされ、refcountは0になります。ロックが解除されます。preg_matchの呼び出しはで動作します。データのコピー、それ自体が元のデータのコピーです。
知っておくべきこと:
データが格納されるオブジェクトストアのハッシュテーブルは、スレッドセーフであり
、ZendによってPHPに付属しているTsHashTableに基づいています。オブジェクトストアには読み取りおよび書き込みロックがあり、TsHashTableに追加のアクセスロックが提供されます。これにより、必要に応じて(var_dump / print_r、PHPエンジンがプロパティを参照したい場合にプロパティに直接アクセスできます)、pthreadがTsHashTableを操作できます。定義されたAPIの外部。
ロックは、コピー操作が行われている間のみ保持され、コピーが作成されると、適切な順序でロックが解除されます。
これの意味は:
書き込みが発生すると、読み取りおよび書き込みロックが保持されるだけでなく、追加のアクセスロックも保持されます。テーブル自体はロックダウンされており、別のコンテキストがテーブルをロック、読み取り、書き込み、または影響を与える可能性はありません。
読み取りが発生すると、読み取りロックが保持されるだけでなく、追加のアクセスロックも保持され、テーブルが再びロックされます。
2つのコンテキストがオブジェクトストアから同じデータに物理的または同時にアクセスすることはできませんが、参照を使用して任意のコンテキストで行われた書き込みは、参照を使用して任意のコンテキストで読み取られたデータに影響します。
これはシェアードナッシングアーキテクチャであり、存在する唯一の方法は共存することです。少し精通している人は、ここで多くのコピーが行われていることを理解し、それが良いことかどうか疑問に思うでしょう。非常に多くのコピーが動的ランタイム内で実行されます。これが動的言語のダイナミクスです。pthreadsはオブジェクトのレベルで実装されます。これは、1つのオブジェクトを適切に制御できるためですが、メソッド(プログラマーが実行するコード)には、ロックやコピーのない別のコンテキスト(ローカルメソッドスコープ)があります。pthreadsオブジェクトの場合のオブジェクトスコープは、コンテキスト間でデータを共有する方法として扱う必要があります。それが目的です。これを念頭に置いて、必要な場合を除いて、オブジェクトストアのロックを回避する手法を採用できます。
PHPで利用できるライブラリと拡張機能のほとんどは、サードパーティの薄いラッパーです。PHPのコア機能はある程度同じです。pthreadsは、Posixスレッドの薄いラッパーではありません。これは、Posixスレッドに基づくスレッドAPIです。PHPでスレッドを実装しても、ユーザーが理解できない、または使用できないという意味はありません。ミューテックスが何であるか、または何をしているのかを知らない人が、スキルとリソースの両方の観点から、持っているすべてを利用できないはずであるという理由はありません。オブジェクトはオブジェクトのように機能しますが、2つのコンテキストが衝突する場合は常に、pthreadsが安定性と安全性を提供します。
Javaで作業したことがある人なら誰でも、pthreadsオブジェクトとJavaでのスレッド化の類似点を理解できます。同じ人々は、ConcurrentModificationExceptionと呼ばれるエラーを目にすることは間違いありません。2つのスレッドが同じ物理データを書き込むと、Javaランタイムによってエラーが発生するためです。同時に。なぜそれが存在するのかは理解できますが、リソースが安価であることに加えて、ランタイムがユーザーの安全を達成できる正確かつ唯一の時間に同時実行を検出できるという事実と相まって、私は困惑しています。実行とデータへのアクセスを管理するのではなく、実行時に致命的なエラーをスローします。
このようなばかげたエラーはpthreadによって発生しません。APIは、スレッドを可能な限り安定させ、互換性を持たせるように作成されていると思います。
マルチスレッドは新しいデータベースを使用するのとは異なり、pthreadに付属しているマニュアルと例のすべての単語に細心の注意を払う必要があります。
最後に、PHPマニュアルから:
pthreadsは、かなり良い結果が得られた実験でした。その制限または機能はいつでも変更される可能性があります。それが実験の本質です。多くの場合、実装によって課せられる制限は、正当な理由で存在します。pthreadの目的は、あらゆるレベルでPHPのマルチタスクに使用できるソリューションを提供することです。pthreadが実行される環境では、安定した環境を提供するためにいくつかの制限と制限が必要です。
Wilcoが提案した例を次に示します。
$cmd = 'nohup nice -n 10 /usr/bin/php -c /path/to/php.ini -f /path/to/php/file.php action=generate var1_id=23 var2_id=35 gen_id=535 > /path/to/log/file.log & echo $!';
$pid = shell_exec($cmd);
基本的に、これはコマンドラインでPHPスクリプトを実行しますが、すぐにPIDを返し、バックグラウンドで実行されます。(echo $!は、PID以外に何も返されないことを保証します。)これにより、必要に応じてPHPスクリプトを続行または終了できます。これを使用すると、ユーザーを別のページにリダイレクトしました。このページでは、5〜60秒ごとにAJAX呼び出しが行われ、レポートがまだ実行されているかどうかが確認されます。(gen_idとそれに関連するユーザーを格納するテーブルがあります。)チェックスクリプトは次のように実行します。
exec('ps ' . $pid , $processState);
if (count($processState) < 2) {
// less than 2 rows in the ps, therefore report is complete
}
このテクニックに関する短い投稿がここにあります:http://nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/
私が知っている利用可能なものは何もありません。次善の策は、あるスクリプトを CLI 経由で別のスクリプトを実行させることですが、それは少し初歩的なことです。あなたがやろうとしていることとそれがどれほど複雑かによって、これがオプションである場合とそうでない場合があります。
要するに、はい、php にはマルチスレッドがありますが、代わりにマルチプロセッシングを使用する必要があります。
背景情報: スレッドとプロセス
スレッドとプロセスの区別については常に多少の混乱があるため、両方について簡単に説明します。
- スレッドは、CPU が処理する一連のコマンドです。それが構成する唯一のデータは、プログラム カウンターです。各 CPU コアは一度に 1 つのスレッドのみを処理しますが、スケジューリングによって異なるスレッドの実行を切り替えることができます。
- プロセスは、共有リソースのセットです。つまり、メモリ、変数、オブジェクト インスタンス、ファイル ハンドル、ミューテックス、データベース接続などの一部で構成されています。各プロセスには、1 つ以上のスレッドも含まれます。同じプロセスのすべてのスレッドはそのリソースを共有するため、あるスレッドで作成した変数を別のスレッドで使用できます。これらのスレッドが 2 つの異なるプロセスの一部である場合、相互のリソースに直接アクセスすることはできません。この場合、パイプ、ファイル、ソケットなどを介したプロセス間通信が必要です...
マルチプロセッシング
php を使用して新しいプロセス (新しいスレッドも含む) を作成することにより、並列計算を実現できます。スレッドがあまり通信や同期を必要としない場合は、プロセスが分離されており、互いの作業に干渉できないため、これを選択します。1つがクラッシュしても、他の人には関係ありません。多くの通信が必要な場合は、「マルチスレッド」を読むか、悲しいことに別のプログラミング言語の使用を検討する必要があります。
PHP では、新しいプロセスを作成する方法が 2 つあります。
OSに任せてください:オペレーティングシステムに新しいプロセスを作成し、その中で新しい(または同じ)phpスクリプトを実行するように指示できます。
Linuxの場合は、次を使用するか、 Darryl Hein の回答を検討してください。
$cmd = 'nice php script.php 2>&1 & echo $!'; pclose(popen($cmd, 'r'));
Windowsの場合、これを使用できます:
$cmd = 'start "processname" /MIN /belownormal cmd /c "script.php 2>&1"'; pclose(popen($cmd, 'r'));
fork で自分でやる: php は、関数pcntl_fork()を介して fork を使用する可能性も提供します。これを行う方法に関する優れたチュートリアルはここにありますが、フォークは人道に対する犯罪、特に oop に対する犯罪であるため、使用しないことを強くお勧めします。
マルチスレッド
マルチスレッドを使用すると、すべてのスレッドがリソースを共有するため、多くのオーバーヘッドなしで簡単に通信して同期できます。反対に、競合状態とデッドロックは簡単に生成できますが、デバッグは非常に難しいため、自分が何をしているのかを知る必要があります。
標準の php はマルチスレッドを提供しませんが、実際にマルチスレッドを提供する (実験的な) 拡張機能 - pthreadsがあります。その API ドキュメントは、それをphp.netにもしました。それを使用すると、実際のプログラミング言語でできることと同じように、次のようなことができます:-):
class MyThread extends Thread {
public function run(){
//do something time consuming
}
}
$t = new MyThread();
if($t->start()){
while($t->isRunning()){
echo ".";
usleep(100);
}
$t->join();
}
Linuxの場合は、stackoverflow にインストール ガイドがあります。
Windowsの場合、現在1つあります:
- まず、php のスレッドセーフ バージョンが必要です。
- pthreads とその php 拡張機能の両方のコンパイル済みバージョンが必要です。それらはここからダウンロードできます。ご使用の PHP バージョンと互換性のあるバージョンをダウンロードしてください。
- php_pthreads.dll (ダウンロードしたばかりの zip から) を php 拡張フォルダー ([phpDirectory]/ext) にコピーします。
- pthreadVC2.dll を [phpDirectory] (拡張フォルダーではなくルート フォルダー) にコピーします。
[phpDirectory]/php.ini を編集し、次の行を挿入します
extension=php_pthreads.dll
上記のスクリプトを使用して、コメントがある場所でスリープまたは何かをテストします。
そして今、大きなBUT : これは実際に機能しますが、php はもともとマルチスレッド用に作成されたものではありません。php のスレッドセーフ バージョンが存在し、v5.4 の時点ではほとんどバグがないように見えますが、マルチスレッド環境で php を使用することは、php マニュアルではまだ推奨されていません (ただし、おそらく彼らは、これは、まだ)。より大きな問題は、多くの一般的な拡張機能がスレッドセーフではないことです。したがって、この php 拡張でスレッドを取得する可能性がありますが、依存している関数はまだスレッドセーフではないため、自分で記述していないコードで競合状態やデッドロックなどが発生する可能性があります...
pcntl_fork()を使用して、スレッドに似たものを実現できます。技術的には別のプロセスなので、両者の通信はスレッドでは簡単ではなく、PHP を apache で呼び出すとうまくいかないと思います。
誰かが気にかけているなら、私はphp_threading (スレッドと同じではありませんが、似ています) を復活させました。
pcntl_fork()
あなたが探しているものですが、そのプロセスはスレッド化ではなく分岐しています。そのため、データ交換の問題が発生します。それらを解決するには、phps セマフォ関数 ( http://www.php.net/manual/de/ref.sem.php ) を使用できます。メッセージ キューは、最初は共有メモリ セグメントよりも簡単かもしれません。
とにかく、私が開発しているWebフレームワークで使用している戦略は、Webページのリソース集約型ブロックをロードします(おそらく外部要求で)並列:ジョブキューを実行して、待っているデータを知り、フォークしますすべてのプロセスのジョブをオフにします。完了すると、親プロセスがアクセスできる一意のキーの下でデータを apc キャッシュに保存します。すべてのデータがそこにあると、それは続きます。Apacheではプロセス間通信ができないため、単純なusleep()
待機を使用しています(子供は親との接続を失い、ゾンビになります...)。最後に、すべての子供を自殺することが重要です。プロセスをフォークするがデータを保持するクラスもあります。私はそれらを調べませんでしたが、zendフレームワークには1つあり、通常は低速ですが確実にコードを実行します。ここで見つけることができます:
http://zendframework.com/manual/1.9/en/zendx.console.process.unix.overview.html
彼らは shm セグメントを使用していると思います! 最後になりましたが、この zend Web サイトにはエラーがあります。例には小さな間違いがあります。
while ($process1->isRunning() && $process2->isRunning()) {
sleep(1);
}
should of course be:
while ($process1->isRunning() || $process2->isRunning()) {
sleep(1);
}
ただの更新ですが、PHPの担当者はスレッドのサポートに取り組んでおり、現在利用可能になっているようです。
これへのリンクは次のとおりです:http: //php.net/manual/en/book.pthreads.php
https://github.com/krakjoe/pthreadsで非常に有望に見えるPThreadsに基づいてアクティブに開発されているスレッド拡張機能があります
私は、本番環境で 2 年以上にわたって問題なく動作している PHP スレッド クラスを持っています。
編集: これは、作曲家ライブラリとして、および私の MVC フレームワークである Hazaar MVC の一部として利用できるようになりました。
これはかなり古い質問だと思いますが、http://phpthreadlib.sourceforge.net/をご覧ください。
双方向通信、Win32 のサポート、および拡張機能は不要です。
技術部門から聞いたことappserver
がありますか?
これは php で書かれており、トラフィックの多い php アプリケーションのマルチスレッドを管理する appserver として機能します。まだベータ版ですが、非常に有望です。
ticksと呼ばれる、かなりあいまいで、すぐに非推奨になる機能があります。私がこれまでに使用した唯一のことは、スクリプトが SIGKILL (Ctrl+C) をキャプチャして正常に終了できるようにすることです。