2013-10-22 44 views
16

我可以使用Guzzle執行單個請求,我對Guzzle的表現非常滿意,但是我在Guzzle API中閱讀了一些關於MultiCurl和Batching的內容。如何同時執行多個Guzzle請求?

有人可以向我解釋如何同時發出多個請求嗎?異步如果可能的話。我不知道這是否與MultiCurl意味着什麼。同步也不是問題。我只想同時或非常接近地完成多個請求(很短的時間)。

+0

在文檔中有一個[此示例](http://guzzlephp.org/http-client/client.html#sending-requests-in-parallel)。從您的角度來看,這仍然是一個同步調用,但內部並行 - 因此調用的總時間只是單次最長提取的時間。 – halfer

回答

16

有關新的GuzzleHttp的更新guzzlehttp/guzzle

併發/並行調用現在通過一些不同的方法執行,包括Promises .. 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問,你也可以使用不同的方法,以避免一組與併發請求的失敗將不會返回所有的迴應。

雖然Pool提出的選項是可行的,但我更喜歡承諾。

承諾的一個例子是使用結算和等待方法,而不是解包。

從例子中的差異上面會

$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中的一個會拋出404錯誤的情況?當發生這種情況時,Guzzle嚇壞了,並拋出一個詭異的例外。 我無法保證URL的可用性,所以我希望只是加載多個請求並使用實際通過的請求。 – georaldc

+0

沒關係,我只是重新做我的代碼來使用GuzzleHttp \ Pool來代替。似乎也工作得很好,給了我更多的控制權。 – georaldc

+1

你能分享你的代碼與多個網站的池嗎? –