プログラムの中では例えプロセス一つ、スレッド一つでも非同期実行にした方が処理が早くなる場合がしばしばあります。これは例えば外部APIを用いた時です。外部のAPIと通信して、外部で処理している間に内部の処理を進めると実行完了までの時間が短くなります。データベースについても同様です。あまり望ましい場合ではありませんがデータベースの中での処理が重いクエリを発行し、データベースが処理を進める間に別のことをする、ということもできます。spatie/async を使うことでこういった非同期処理を簡単に書けます。
spatie/async: Easily run code asynchronously
インストールは composer でできます。
composer require spatie/async
spatie/async の使い方は次です。
<?php // プログラムの実行時間をざっくり計測するために用意します。 // 実行に約5秒かかるプログラムをshell_execで2回呼び出した時、10秒かかるか5秒だけかかるか見るために用意します。 $start = microtime(true); // spatie/asyncを使うために用意します。 require_once __DIR__ . '/vendor/autoload.php'; use Spatie\Async\Pool; // Poolはspatie/async の用意したクラスでこのインスタンスの中に非同期処理したい処理を追加していきます。 $pool = Pool::create(); // このように実行したい処理を関数呼び出しできる形で追加していきます。 // Spatie\Async\Process\Runnable というインターフェースを実装したクラスを追加することもできます。 $pool->add(function () { // shell_execでPHPのスクリプトを実行しています。 // このスクリプトは5秒間sleepしてからHello, World!と出力するプログラムです。 return shell_exec('php tmp.5secSleep.php'); }); $pool->add(function () { return shell_exec('php tmp.5secSleep.php'); }); echo "今非同期実行処理が動いている横で動いてます\n"; // wait()を呼び出すと、追加した処理が全て終わるまで待ちます。 // wait()の戻り値は、追加した処理の結果を配列で返します。 $result = $pool->wait(); // 結果を出力します。 var_dump($result); /* array(2) { [0]=> string(13) "Hello, World!" [1]=> string(13) "Hello, World!" } */ echo 'Time: '.round(microtime(true) - $start).PHP_EOL; // Time: 5
こんな感じで JavaScript の Promise みたいな感じで使えます。
また多くの言語にある async, await 的な挙動も次の様に書けます。
<?php // プログラムの実行時間をざっくり計測するために用意します。 // 実行に約5秒かかるプログラムをshell_execで2回呼び出した時、10秒かかるか5秒だけかかるか見るために用意します。 $start = microtime(true); // spatie/asyncを使うために用意します。 require_once __DIR__ . '/vendor/autoload.php'; use Spatie\Async\Pool; // async 関数が使える様になります。これは非同期実行されます。 $task1 = async(function () { return shell_exec('php tmp.5secSleep.php'); }); $task2 = async(function () { return shell_exec('php tmp.5secSleep.php'); }); echo "今非同期実行処理が動いている横で動いてます\n"; // Poolには後から非同期処理を追加することもできます。 $pool = Pool::create(); $pool->add($task1); $pool->add($task2); // await()にPoolを渡すと、追加した処理が全て終わるまで待ちます。 // 返り値は Pool::class の wait() と同じです。 $result = await($pool); // 結果を出力します。 var_dump($result); /* array(2) { [0]=> string(13) "Hello, World!" [1]=> string(13) "Hello, World!" } */ echo 'Time: '.round(microtime(true) - $start).PHP_EOL; // Time: 5
spatie/asyncライブラリを利用すると、PHPでの非同期処理が簡単かつ効率的に実行できます。外部APIやデータベースとの通信などがあり、その完了を待つ前に色々とできる場合、その待つ間を有効活用するのに便利です。特に同時に複数のリクエストやクエリを発行して全て完了するまで待つような時は有効に活用しやすいです。spatie/asyncを使用することで、アプリケーションのレスポンス時間を短縮しやすくなります。