web-dev-qa-db-ja.com

PHPにはスレッドがありますか?

これを見つけました スレッドと呼ばれるPECLパッケージ ですが、まだリリースがありません。 PHPウェブサイトには何も掲載されていません。

125
Thomas Owens

私が知っている利用可能なものは何もありません。次の最良の方法は、CLIを使用して1つのスクリプトに別のスクリプトを実行させることですが、それは少し初歩的なことです。あなたがしようとしていることとそれがどれほど複雑かによって、これはオプションかもしれませんし、そうでないかもしれません。

40
Wilco

pthreads 拡張のPHPマニュアルから:

pthreadsは、PHPでユーザーランドのマルチスレッドを可能にするオブジェクト指向APIです。これには、Webまたはコンソールを対象とするマルチスレッドアプリケーションを作成するために必要なすべてのツールが含まれています。 PHPアプリケーションは、スレッド、ワーカー、およびスタッカブルを作成、読み取り、書き込み、実行、および同期できます。

これは信じられないほど聞こえますが、完全に真実です。今日、PHPは、試してみたい人のためにマルチスレッド化できます。

2000年5月22日のPHP4の最初のリリースPHPは、スレッドセーフアーキテクチャで出荷されました。マルチスレッドSAPI(サーバーAPI)環境の個別のスレッドでインタープリターの複数のインスタンスを実行する方法です。過去13年間にわたって、このアーキテクチャの設計は維持され、高度化されています。それ以来、世界最大のWebサイトで実稼働で使用されています。

ユーザーランドでのスレッド化はPHPチームにとって懸念事項ではありませんでしたが、今日でもそのままです。 PHPがビジネスをしている世界では、既に定義されたスケーリング方法があります-ハードウェアを追加してください。長年にわたってPHPが存在し、ハードウェアはどんどん安くなってきたため、PHPチームにとっての懸念はますます少なくなりました。安くなっていたが、はるかに強力になった。今日、携帯電話とタブレットはデュアルおよびクアッドコアアーキテクチャを備えており、多くのRAMに対応しています。デスクトップとサーバーには通常8コアまたは16コア、16ギガバイトと32ギガバイトのRAMがあります。常に予算内で2台を使用でき、ほとんどの場合、2台のデスクトップを使用することはほとんど役に立ちません。

さらに、PHPはプログラマーではない人のために書かれており、多くの愛好家が母国語です。 PHPが非常に簡単に採用される理由は、学習と記述が簡単な言語だからです。 PHPが今日非常に信頼できる理由は、その設計に費やされる膨大な量の作業と、PHPグループによって行われるすべての決定のためです。信頼性と素晴らしさは、これらすべての年月を経て、注目を浴びています。ライバルは、時間やプレッシャーに負けています。

マルチスレッドプログラミングは、最も一貫性があり信頼性の高いAPIを使用しても、ほとんどの人にとって簡単ではありません。さまざまな考え方があり、多くの誤解があります。 PHPグループは、ユーザーランドのマルチスレッド化がコア機能であることを望みません。それは深刻な注目を浴びたことはありませんでした-そして当然です。 PHPは誰にとっても複雑であってはなりません。

すべてを考慮すると、PHPがプロダクション対応のテスト済みの機能を利用できるようにすることで得られる利点があります。オプション、および多くのタスクのために本当に必要とされることはありません。

pthreadは、ユーザーがマルチスレッドPHPアプリケーションを使用できるようにするAPIを、それを探求したい人のために実現しています。 APIは非常に進行中の作業であり、ベータレベルの安定性と完全性を指定しています。

ライブラリPHPの使用の一部はスレッドセーフではないことはよく知られています。pthreadsはこれを変更できず、試行もしないことをプログラマーに明確に伝える必要があります。ただし、スレッドセーフなライブラリは、インタープリターの他のスレッドセーフセットアップと同様に使用できます。

pthreadsはPosixスレッド(Windowsでも)を利用し、プログラマーが作成するのは実際の実行スレッドですが、これらのスレッドが役立つためには、PHP-ユーザーコードの実行、変数の共有、便利な通信手段(同期)を許可します。したがって、すべてのスレッドはインタープリターのインスタンスで作成されますが、設計上、インタープリターは、マルチスレッドサーバーAPI環境のように、インタープリターの他のすべてのインスタンスから分離されます。 pthreadは、健全で安全な方法でギャップを埋めようとします。 Cのスレッドのプログラマーの懸念の多くは、pthreadのプログラマーにはありません。設計上、pthreadは読み取り時のコピーと書き込み時のコピーであるため(RAMは安価です)、2つのインスタンスはありません同じ物理データを操作することはありますが、両方とも別のスレッドのデータに影響を与える可能性があります。 PHPがコアプログラミングでスレッドセーフでない機能を使用する可能性があるという事実はまったく無関係であり、ユーザースレッドであり、その操作は完全に安全です。

読み取り時のコピーと書き込み時のコピーの理由:

public function run() {
    ...
    (1) $this->data = $data;
    ...
    (2) $this->other = someOperation($this->data);
    ...
}

(3) echo preg_match($pattern, $replace, $thread->data);

(1)読み取りおよび書き込みロックがpthreadsオブジェクトデータストアで保持されている間、データはメモリ内の元の場所からオブジェクトストアにコピーされます。 pthreadsは変数の参照カウントを調整しません。Zendは、それへの参照がなければ元のデータを解放できます。

(2)someOperationへの引数はオブジェクトストアを参照します。保存された元のデータ自体は(1)の結果のコピーであり、エンジン用にzvalコンテナーに再度コピーされますが、読み取りロックが保持されます。オブジェクトストア、ロックが解除され、エンジンが機能を実行できます。 zvalが作成されると、参照カウントが0になり、操作への参照が他にないため、エンジンは操作の完了時にコピーを解放できます。

(3)preg_matchの最後の引数はデータストアを参照し、読み取りロックが取得され、(1)のデータセットがrefcountを0にしてzvalにコピーされます。ロックが解放され、preg_matchの呼び出しが実行されますデータのコピー。それ自体が元のデータのコピーです。

知っておくべきこと:

  • データが保存されるオブジェクトストアのハッシュテーブルは、スレッドセーフです。
    PHPに同梱されているTsHashTableに基づくZend。

  • オブジェクトストアには読み取りおよび書き込みロックがあり、TsHashTableに追加のアクセスロックが提供されているため、必要な場合(およびvar_dump/print_rがPHPエンジンがそれらを参照したいときにプロパティに直接アクセスできます) )pthreadは、定義されたAPIの外部でTsHashTableを操作できます。

  • ロックは、コピー操作が行われている間のみ保持され、コピーが作成されると、ロックは適切な順序で解放されます。

これは次を意味します:

  • 書き込みが発生すると、読み取りおよび書き込みロックが保持されるだけでなく、追加のアクセスロックが保持されます。テーブル自体はロックダウンされています。別のコンテキストがロック、読み取り、書き込み、または影響を与える可能性はありません。

  • 読み取りが発生すると、読み取りロックが保持されるだけでなく、追加のアクセスロックも保持され、再びテーブルがロックダウンされます。

2つのコンテキストが物理的にも同時にオブジェクトストアの同じデータにアクセスすることはできませんが、参照を含む任意のコンテキストで行われた書き込みは、参照を含む任意のコンテキストで読み取られたデータに影響します。

これは何も共有しないアーキテクチャであり、存在する唯一の方法は共存することです。少し精通している人は、ここで多くのコピーが行われていることを理解し、それが良いことかどうか疑問に思うでしょう。動的ランタイム内でかなり多くのコピーが行われます。それが動的言語のダイナミクスです。 pthreadはオブジェクトのレベルで実装されます。1つのオブジェクトを適切に制御できるためですが、メソッド(プログラマーが実行するコード)には、ロックとコピーのない別のコンテキスト(ローカルメソッドスコープ)があります。 pthreadsオブジェクトの場合のオブジェクトスコープは、コンテキスト間でデータを共有する方法として扱う必要があります。それが目的です。これを念頭に置いて、ローカルスコープ変数を実行時にオブジェクトストアからコピーするのではなく、スレッドオブジェクトの他のメソッドに渡すなど、必要でない限りオブジェクトストアのロックを回避する手法を採用できます。

PHPで使用できるライブラリと拡張機能のほとんどは、サードパーティのシンラッパーです。PHPコア機能はある程度同じです。 pthreadsは、Posixスレッドの薄いラッパーではありません。 Posix Threadsに基づくスレッド化APIです。 PHPにスレッドを実装しても、ユーザーが理解できない、または使用できないという意味はありません。ミューテックスが何であるか、またはミューテックスについて何も知らない人が、スキルとリソースの両方の面で、自分が持っているすべてを活用できない理由はありません。オブジェクトはオブジェクトのように機能しますが、2つのコンテキストが衝突する場合はいつでも、pthreadは安定性と安全性を提供します。

Javaで作業した人は誰でもpthreadsオブジェクトとJavaのスレッドの類似点を見ることができます。同じ人々は間違いなくConcurrentModificationExceptionと呼ばれるエラーを見るでしょう-Java 2つのスレッドが同じ物理データを同時に書き込む場合のランタイム。私はそれが存在する理由を理解していますが、リソースができるだけ安価であり、ユーザーが安全を達成できる正確かつ唯一の時間でランタイムが並行性を検出できるという事実と相まって、実行とデータへのアクセスを管理するのではなく、実行時に致命的なエラーをスローします。

このような愚かなエラーはpthreadによって発生することはありません。APIは、スレッドを可能な限り安定させ、互換性を保つように作成されています。

マルチスレッドは新しいデータベースを使用するようなものではありません。マニュアルとpthreadに同梱されているサンプルのすべてのWordに細心の注意を払う必要があります。

最後に、PHPマニュアルから:

pthreadは、これまでも現在も、かなり良い結果が得られた実験です。その制限または機能は、いつでも変更される可能性があります。それが実験の性質です。それには制限があります-多くの場合実装によって課せられます-正当な理由で存在します。 pthreadの目的は、任意のレベルのPHPでマルチタスクに使用可能なソリューションを提供することです。 pthreadが実行される環境では、安定した環境を提供するために、いくつかの制限と制限が必要です。

176
Joe Watkins

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とそれが関連するユーザーを保存するテーブルがあります。)checkスクリプトは次を実行します:

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/

48
Darryl Hein

要するに、はい、PHPにはマルチスレッドがありますが、代わりにマルチプロセッシングを使用する必要があります。

背景情報:スレッドとプロセス

スレッドとプロセスの区別については常に少し混乱があるため、両方を簡単に説明します。

  • threadは、CPUが処理する一連のコマンドです。それが構成される唯一のデータはプログラムカウンターです。各CPUコアは一度に1つのスレッドのみを処理しますが、スケジューリングにより異なるスレッドの実行を切り替えることができます。
  • processは、共有リソースのセットです。つまり、メモリ、変数、オブジェクトインスタンス、ファイルハンドル、ミューテックス、データベース接続などの一部で構成されます。各プロセスには、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'));
    

フォークで自分でやる:phpは、関数 pcntl_fork() を介してフォークを使用する可能性も提供します。これを行う方法に関する良いチュートリアルは こちら で見つけることができますが、 フォークは人道に対する罪であるため 、特に使用しないことを強くお勧めしますおっと。

マルチスレッド

マルチスレッドを使用すると、すべてのスレッドがリソースを共有するので、多くのオーバーヘッドなしで簡単に通信および同期できます。一方、競合状態とデッドロックは簡単に生成できますが、デバッグは非常に難しいため、何をしているのかを知る必要があります。

標準の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'sに インストールガイド があります。

windowsの場合、現在1つあります。

  • まず、スレッドセーフバージョンのphpが必要です。
  • Pthreadとその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 manual (しかし、彼らはまだこれに関するマニュアルを更新していなかったかもしれません)。はるかに大きな問題は、多くの一般的な 拡張機能がスレッドセーフではないことです 。したがって、このPHP拡張機能でスレッドを取得するかもしれませんが、依存している関数はまだスレッドセーフではないため、おそらく自分で書いていないコードで競合状態やデッドロックなどが発生します...

24

pcntl_fork() を使用して、スレッドに似たものを実現できます。技術的には独立したプロセスなので、スレッド間の2つの通信はそれほど単純ではなく、PHPがApacheによって呼び出された場合は機能しないと思います。

17
davr

誰か気になったら、私は復活しましたphp_threading(スレッドと同じではありませんが、似ています)そして実際に動作するところまで持っています(ある程度)まあ!

プロジェクトページ

ダウンロード(Windowsの場合PHP 5.3 VC9 TS)

README

13
Alec Gorge

pcntl_fork()は検索対象ですが、そのプロセスはスレッド化ではありません。そのため、データ交換の問題が発生します。それらを解決するには、PHPのセマフォ関数を使用することができます( http://www.php.net/manual/de/ref.sem.php )メッセージキューは共有メモリよりも最初は少し簡単かもしれませんセグメント。

とにかく、私が開発しているWebフレームワークで使用している戦略は、Webページのリソース集中ブロックを(おそらく外部リクエストで)並列にロードします:私は待っているデータを知るためにジョブキューをしていて、フォークしますすべてのプロセスのジョブをオフにします。完了すると、親プロセスがアクセスできる一意のキーの下でapcキャッシュにデータを保存します。すべてのデータがそこにあると、それは継続します。 Apacheではプロセス間通信ができないため、単純なusleep()を使用して待機しています(子供は親との接続を失い、ゾンビになります...)。だからこれは私に最後のことをもたらします:すべての子供を自殺することが重要です!プロセスをフォークするがデータを保持するクラスもあります。私はそれらを調べませんでしたが、zendフレームワークにはそれがあり、通常は低速ですが確実にコードを実行します。あなたはここでそれを見つけることができます: 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);
}
7
The Surrican

ただの更新で、PHP連中がスレッドのサポートに取り組んでいるようで、現在利用可能です。

リンクは次のとおりです。 http://php.net/manual/en/book.pthreads.php

6
happyhardik

https://github.com/krakjoe/pthreads で非常に有望に見えるPThreadsに基づいて開発されているactivleyであるThreading拡張機能があります

6
JasonDavis

PHPスレッドクラスがあり、現在2年以上にわたって運用環境で問題なく実行されています。

編集:これはcomposerライブラリとして、また私のMVCフレームワークであるHazaar MVCの一部として利用可能になりました。

参照: https://git.hazaarlabs.com/hazaar/hazaar-thread

5
Jamie Carl

私はこれがかなり古い質問であることを知っていますが、あなたは http://phpthreadlib.sourceforge.net/ を見ることができます

双方向通信、Win32のサポート、および拡張機能は不要です。

2
Unsigned

技術部門からappserverについて聞いたことはありますか?

これはphpで書かれており、トラフィックの多いphpアプリケーションのマルチスレッドを管理するアプリサーバーとして機能します。まだベータ版ですが、非常に普及しています。

1
user2627170