2013-10-22 21 views
16

私はGuzzleを使用して1つのリクエストを実行できますが、Guzzleのパフォーマンスは非常に満足しています。しかし、Guzzle APIでMultiCurlとBatchingについて読んでいます。複数のGuzzleリクエストを同時に実行するにはどうすればよいですか?

誰かが複数のリクエストを同時に行う方法を教えてもらえますか?可能であれば非同期。それがMultiCurlで意味するものなのかどうかはわかりません。同期も問題ではありません。私はちょうど同時に、または非常に近い(時間の短いスペース)で複数のリクエストをしたい。ドキュメントから

+0

ドキュメントに[このデモ](http://guzzlephp.org/http-client/client.html#sending-requests-in-parallel)があります。これは、あなたの視点からはまだ同期呼び出しですが、内部的には並列になります。したがって、呼び出しの合計時間は、1つの最も長いフェッチの時間になります。 – halfer

答えて

18

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') 
)); 
16

新しいGuzzleに関連する更新プログラムguzzhttp/guzzle

並行/並行呼び出しは、約束を含むいくつかの異なる方法で実行されます。Concurrent Requests

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

更新例ここ

$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)); 

を参照してください: コメントで提案されているとの@ sankalp-tambeで尋ねたとして、あなたはまたして同時リクエストのセットを回避するために異なるアプローチを使用することができます失敗するとすべての応答が返されません。

プールで提案されているオプションは実現可能ですが、私はまだ約束を優先します。

例では、unwrapの代わりにsettleおよびwaitメソッドを使用します。上記の例から

違いは、私があまりにも$応答を処理する方法の参考のために、以下の完全な例を作成しました

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

だろう。

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と掲載されていました。

+0

これは、複数の画像URLのデータを一度に読み込む場合には役に立ちますが、ロードされているURLの1つが404エラーをスローする状況をどのように処理できますか?これが起こると、Guzzleが鳴り出してグレッグの例外がスローされます。 URLの可用性を保証することはできませんので、複数のリクエストをロードして実際に通過するリクエストを使用することを望んでいました。 – georaldc

+0

心配しないで、GuzzleHttp \ Poolを代わりに使用するようにコードを再作成しました。うまく動作するように見え、私にもう少しコントロールを与えます。 – georaldc

+1

複数のURLのコードをプールと共有できますか? –