非同期でHTTPリクエストができるGuzzleを試してみたメモ。
内部的にはcurl_multiを使っているそうです。
インストール
composerを使ってインストールします。
$ composer require guzzlehttp/guzzle
使い方
非同期でHTTPリクエストを投げるコードがこちら。
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Promise;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\RequestException;
$client = new Client();
$promises = [];
for($i = 0; $i < 10; ++$i){
$promise = $client->requestAsync('GET', 'http://httpbin.org');
$promise->then(
// Fullfilled
function(ResponseInterface $res){
echo $res->getStatusCode() . "\n";
},
//Rejected
function(RequestException $e) {
echo $e->getMessage() . "\n";
echo $e->getRequest()->getMethod();
}
);
$promises[] = $promise;
}
Promise\all($promises)->wait();
-
Guzzleには、非同期でリクエストするためのメソッドが複数用意されています。
上記のコードでは、requestAsync()
を使ってます。
http://docs.guzzlephp.org/en/stable/quickstart.html#async-requests -
非同期リクエスト用のメソッドは、Promise/A+の仕様で実装されているので、仕様に沿って
then()
で成功時と失敗時に呼び出す関数を設定します。
https://promisesaplus.com/
が、この方法だとPromiseオブジェクトがメモリを食うため、foreach()でメモリオーバーで落ちる可能性があるらしい。
この問題を回避するために使えるものが、Poolオブジェクト。
先ほどのコードをPoolオブジェクトを使う方法で書き換えたものが下記のコード。ジェネレータを使ってます。
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Promise;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Pool;
$client = new Client();
$requests = function() use ($client) {
for($i = 0; $i < 10; ++$i){
yield function() use ($client) {
$promise = $client->requestAsync('GET', 'http://httpbin.org');
$promise->then(
// Fullfilled
function(ResponseInterface $res){
echo $res->getStatusCode() . "\n";
},
//Rejected
function(RequestException $e) {
echo $e->getMessage() . "\n";
echo $e->getRequest()->getMethod();
}
);
return $promise;
};
}
};
$pool = new Pool($client, $requests());
$promise = $pool->promise();
$promise->wait();