web-dev-qa-db-ja.com

複数のGuzzleリクエストを同時に実行する方法は?

Guzzleを使用して単一のリクエストを実行できますが、これまでのところGuzzleのパフォーマンスに非常に満足していますが、Guzzle APIでMultiCurlとバッチ処理について読んでいます。

誰かが複数のリクエストを同時に行う方法を説明してもらえますか?可能な場合は非同期。それがMultiCurlで何を意味するのかわかりません。同期も問題になりません。複数のリクエストを同時に、または非常に近い時間(短い時間)で実行したいだけです。

22
Martijn

ドキュメントから: http://guzzle3.readthedocs.org/http-client/client.html#sending-requests-in-parallel

応答またはエラーにマッピングするリクエストオブジェクトのハッシュを返す使いやすいソリューションについては、 http://guzzle3.readthedocs.org/batching/batching.html#batching をご覧ください。

短い例:

<?php

$client->send(array(
    $client->get('http://www.example.com/foo'),
    $client->get('http://www.example.com/baz'),
    $client->get('http://www.example.com/bar')
));
22
Michael Dowling

新しいGuzzleHttpguzzlehttp/guzzleに関連する更新

同時/並列呼び出しは、Promisesを含むいくつかの異なる方法で実行されるようになりました。 Concurrent Requests

RequestInterfacesの配列を渡す古い方法はもう機能しません。

例を参照してくださいhere

    $newClient = new  \GuzzleHttp\Client(['base_uri' => $base]);
    foreach($documents->documents as $doc){

        $params = [
            'language' =>'eng',
            'text' => $doc->summary,
            'apikey' => $key
        ];

        $requestArr[$doc->reference] = $newClient->getAsync( '/1/api/sync/analyze/v1?' . http_build_query( $params) );
    }

    $time_start = microtime(true);
    $responses = \GuzzleHttp\Promise\unwrap($requestArr); //$newClient->send( $requestArr );
    $time_end = microtime(true);
    $this->get('logger')->error(' NewsPerf Dev: took ' . ($time_end - $time_start) );

Update:@ sankalp-tambeのコメントおよび提案で示唆されているように、異なるアプローチを使用して、失敗した同時リクエストのセットを回避することもできますすべての応答を返しません。

プールで提案されたオプションは実行可能ですが、私はまだ約束を好みます。

Promiseの例は、アンラップの代わりにsettleおよびwaitメソッドを使用することです。

上記の例との違いは

$responses = \GuzzleHttp\Promise\settle($requestArr)->wait(); 

$ responsesを処理する方法についての参照用に、以下の完全な例を作成しました。

require __DIR__ . '/vendor/autoload.php';
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Promise as GuzzlePromise;

$client = new GuzzleClient(['timeout' => 12.0]); // see how i set a timeout
$requestPromises = [];
$sitesArray = SiteEntity->getAll(); // returns an array with objects that contain a domain

foreach ($sitesArray as $site) {
    $requestPromises[$site->getDomain()] = $client->getAsync('http://' . $site->getDomain());
}

$results = GuzzlePromise\settle($requestPromises)->wait();

foreach ($results as $domain => $result) {
    $site = $sitesArray[$domain];
    $this->logger->info('Crawler FetchHomePages: domain check ' . $domain);

    if ($result['state'] === 'fulfilled') {
        $response = $result['value'];
        if ($response->getStatusCode() == 200) {
            $site->setHtml($response->getBody());
        } else {
            $site->setHtml($response->getStatusCode());
        }
    } else if ($result['state'] === 'rejected') { 
        // notice that if call fails guzzle returns is as state rejected with a reason.

        $site->setHtml('ERR: ' . $result['reason']);
    } else {
        $site->setHtml('ERR: unknown exception ');
        $this->logger->err('Crawler FetchHomePages: unknown fetch fail domain: ' . $domain);
    }

    $this->entityManager->persist($site); // this is a call to Doctrines entity manager
}

このサンプルコードは元々投稿されていました here

23
Bizmate

Guzzle 6.0では、複数の非同期リクエストの送信が非常に簡単になりました。

それを行うには複数の方法があります。

非同期リクエストを作成し、結果のプロミスを単一の配列に追加し、次のようなsettle()メソッドを使用して結果を取得できます。

_$promise1 = $client->getAsync('http://www.example.com/foo1');
$promise2 = $client->getAsync('http://www.example.com/foo2');
$promises = [$promise1, $promise2];

$results = GuzzleHttp\Promise\settle($promises)->wait();
_

これで、これらの結果をループし、GuzzleHttpPromiseallまたはGuzzleHttpPromiseeachを使用して応答をフェッチできます。詳細については この記事 を参照してください。

送信するリクエストの数が不定の場合(ここでは5つ)、GuzzleHttp/Pool::batch()を使用できます。次に例を示します。

_$client = new Client();

// Create the requests
$requests = function ($total) use($client) {
    for ($i = 1; $i <= $total; $i++) {
        yield new Request('GET', 'http://www.example.com/foo' . $i);
    }
};

// Use the Pool::batch()
$pool_batch = Pool::batch($client, $requests(5));
foreach ($pool_batch as $pool => $res) {

    if ($res instanceof RequestException) {
        // Do sth
        continue;
    }

    // Do sth
}
_
0
Annapurna