このライブラリは、PHP の PCNTL 拡張機能の小さくて簡単なラッパーを提供します。使いやすい API を使用して、さまざまなプロセスを並行して実行できます。
私たちはクラス最高のオープンソース パッケージの作成に多くのリソースを投資しています。有料製品のいずれかを購入することで、私たちをサポートできます。
当社のどのパッケージを使用しているかについて、故郷から葉書を送っていただき、誠にありがとうございます。当社の住所は、お問い合わせページに記載されています。受け取ったすべてのポストカードをバーチャル ポストカード ウォールに公開します。
パッケージは、composer 経由でインストールできます。
composer require spatie/async
use Spatie Async Pool ;
$ pool = Pool:: create ();
foreach ( $ things as $ thing ) {
$ pool -> add ( function () use ( $ thing ) {
/ / Do a thing
})-> then ( function ( $ output ) {
/ / Handle success
})-> catch ( function ( Throwable $ exception ) {
/ / Handle exception
});
}
$ pool -> wait ();
非同期プロセスを作成すると、 ParallelProcess
のインスタンスが返されます。次のイベント フックをプロセスに追加できます。
$ pool
-> add ( function () {
/ / ...
})
-> then ( function ( $ output ) {
/ / On success , `$output` is returned by the process or callable you passed to the queue .
})
-> catch ( function ( $ exception ) {
/ / When an exception is thrown from within a process , it 's caught and passed here.
})
-> timeout ( function () {
/ / A process took too long to finish.
})
;
$pool
オブジェクトのメソッドを使用する代わりに、 async
およびawait
ヘルパー関数を使用することもできます。
use Spatie Async Pool ;
$ pool = Pool:: create ();
foreach ( range ( 1 , 5 ) as $ i ) {
$ pool [] = async ( function () {
usleep ( random_int ( 10 , 1000 ));
return 2 ;
})-> then ( function ( int $ output ) {
$ this -> counter += $ output ;
});
}
await ( $ pool );
子プロセス内からException
またはError
がスローされた場合、 ->catch()
メソッドでコールバックを指定することで、プロセスごとに例外またはエラーをキャッチできます。
$ pool
-> add ( function () {
/ / ...
})
-> catch ( function ( $ exception ) {
/ / Handle the thrown exception for this child process.
})
;
エラー ハンドラーが追加されていない場合、 await()
または$pool->wait()
を呼び出すときに親プロセスでエラーがスローされます。
子プロセスがThrowable
をスローせずに予期せず停止した場合、 stderr
に書き込まれた出力はラップされ、親プロセスでSpatieAsyncParallelError
としてスローされます。
catch
関数をタイプヒントすることにより、個別の種類のエラーに対して複数のエラー ハンドラーを提供できます。
$ pool
-> add ( function () {
throw new MyException ( ' test ' );
})
-> catch ( function ( MyException $ e ) {
/ / Handle `MyException`
})
-> catch ( function ( OtherException $ e ) {
/ / Handle `OtherException`
});
例外が処理されるとすぐに、他のハンドラーはトリガーされないことに注意してください。
$ pool
-> add ( function () {
throw new MyException ( ' test ' );
})
-> catch ( function ( MyException $ e ) {
/ / This one is triggerd when `MyException` is thrown
})
-> catch ( function ( Exception $ e ) {
/ / This one is not triggerd , even though `M yException ` extends `E xception `
});
プールが実行していたタスクが子プロセスの 1 つによって完了したため、プールを早期に停止する必要がある場合は、 $pool->stop()
メソッドを使用できます。これにより、プールが追加のプロセスを開始できなくなります。
use Spatie Async Pool ;
$ pool = Pool:: create ();
/ / Generate 10 k processes generating random numbers
for ( $ i = 0 ; $ i < 10000 ; $ i ++) {
$ pool -> add ( function () use ( $ i ) {
return rand ( 0 , 100 );
})-> then ( function ( $ output ) use ( $ pool ) {
/ / If one of them randomly picks 100 , end the pool early .
if ( $ output === 100 ) {
$ pool -> stop ();
}
});
}
$ pool -> wait ();
プールは停止すると使用できなくなるため、必要に応じて新しいプールを作成する必要があることに注意してください。
デフォルトでは、プールはphp
使用して子プロセスを実行します。次のように別のバイナリを設定できます。
Pool:: create ()
-> withBinary ( ' /path/to/php ' );
クロージャを使用する以外に、 Task
を操作することもできます。 Task
、子プロセスでさらにセットアップ作業が必要な場合に役立ちます。子プロセスは常に何もない状態からブートストラップされるため、おそらく初期化する必要があるでしょう。タスクを実行する前に依存関係コンテナーを確認します。 Task
クラスを使用すると、これが簡単になります。
use Spatie Async Task ;
class MyTask extends Task
{
public function configure ()
{
/ / Setup eg . dependency container , load config , ...
}
public function run ()
{
/ / Do the real work here.
}
}
/ / Add the task to the pool
$ pool -> add ( new MyTask ());
タスクのロジックをカプセル化したいが、本格的なTask
オブジェクトを作成したくない場合は、呼び出し可能なオブジェクトをPool
に渡すこともできます。
class InvokableClass
{
/ / ...
public function __invoke ()
{
/ / ...
}
}
$ pool -> add ( new InvokableClass ( / * ... * / ));
必要なだけプールを自由に作成できます。各プールには、処理するプロセスの独自のキューがあります。
プールは開発者によって構成可能です。
use Spatie Async Pool ;
$ pool = Pool:: create ()
/ / The maximum amount of processes which can run simultaneously.
-> concurrency ( 20 )
/ / The maximum amount of time a process may take to finish in seconds
/ / ( decimal places are supported for more granular timeouts ) .
-> timeout ( 15 )
/ / Configure which autoloader sub processes should use.
-> autoload ( __DIR__ . ' /../../vendor/autoload.php ' )
/ / Configure how long the loop should sleep before re - checking the process statuses in microseconds .
-> sleepTime ( 50000 )
;
必要な拡張機能 ( pcntl
およびposix
) が現在の PHP ランタイムにインストールされていない場合、 Pool
自動的にタスクの同期実行にフォールバックします。
Pool
クラスには、プラットフォームが非同期プロセスを実行できるかどうかを確認するために呼び出すことができる静的メソッドisSupported
があります。
Task
使用してプロセスを実行している場合、同期モードでの実行時には、それらのタスクのrun
メソッドのみが呼び出されます。
このパッケージを使用するとき、おそらく表面下で何が起こっているのか疑問に思うでしょう。
PHP で子プロセスを作成および管理するためにsymfony/process
コンポーネントを使用しています。子プロセスをオンザフライで作成することで、PHP スクリプトを並行して実行できます。この並列処理により、実際には相互に待機する必要のない複数の同期タスクを処理する際のパフォーマンスが大幅に向上します。これらのタスクに実行する別のプロセスを与えることで、基礎となるオペレーティング システムがそれらのタスクを並行して実行できるようになります。
プロセスを動的に生成する場合は注意点があります。一度にプロセスが多すぎないように注意する必要があります。そうしないと、アプリケーションがクラッシュする可能性があります。このパッケージで提供されるPool
クラスは、可能なときにプロセスをスケジュールして実行することで、必要な数のプロセスを処理します。
これは、 async()
または$pool->add()
が行う部分です。ここで、 await()
または$pool->wait()
何を行うかを見てみましょう。
複数のプロセスが生成される場合、それぞれのプロセスが完了するまでに別々の時間がかかる可能性があります。 1 つのプロセスは次のようになります。一方は HTTP 呼び出しを待つ必要があり、もう一方は大量のデータを処理する必要があります。場合によっては、コード内にプロセスの結果が返されるまで待機する必要があるポイントがあることもあります。
これが、特定の時点で待機する必要がある理由です。つまり、プール上のすべてのプロセスが完了するまで待機する必要があるため、まだ完了していない子プロセスを誤って強制終了することなく、安全に続行できることを確認できます。
すべてのプロセスの待機は、 while
ループを使用して行われ、すべてのプロセスが終了するまで待機します。プロセスがいつ終了するかは、 SIGCHLD
シグナルのリスナーを使用して判断されます。このシグナルは、OS カーネルによって子プロセスが終了したときに発行されます。 PHP 7.1 の時点では、シグナルのリスニングと処理のサポートが大幅に向上しており、このアプローチは、たとえば、通信にプロセス フォークまたはソケットを使用します。詳細については、こちらをご覧ください。
プロセスが終了すると、その成功イベントがトリガーされ、 ->then()
関数でフックできます。同様に、プロセスが失敗するかタイムアウトになると、ループはそのプロセスのステータスを更新して次に進みます。すべてのプロセスが終了すると、while ループは待機するものがなくなったことを確認して停止します。これは、親プロセスが実行を継続できる瞬間です。
このパッケージの使用例に関する詳細と、ReactPHP や Amp などの他の非同期 PHP ライブラリとの比較を含むブログ投稿を書きました (http://stitcher.io/blog/asynchronous-php)。
composer test
最近の変更点の詳細については、CHANGELOG を参照してください。
詳細については、「貢献」を参照してください。
セキュリティに関するバグを見つけた場合は、問題トラッカーを使用する代わりに [email protected] にメールを送信してください。
このパッケージを自由に使用できますが、実稼働環境に届いた場合は、どのパッケージを使用しているかを記載した葉書を故郷から送っていただければ幸いです。
私たちの住所は、Spatie, Kruikstraat 22, 2018 Antwerp, Belgiumです。
いただいたはがきはすべて当社ホームページに掲載しております。
MIT ライセンス (MIT)。詳細については、ライセンス ファイルを参照してください。