2013-10-22 22 views
16

Tôi có thể thực hiện yêu cầu duy nhất bằng cách sử dụng Guzzle và tôi rất hài lòng với hiệu suất của Guzzle cho đến nay tuy nhiên, tôi đọc trong API Guzzle một cái gì đó về MultiCurl và Batching.Làm thế nào để thực hiện nhiều yêu cầu Guzzle cùng một lúc?

Ai đó có thể giải thích cho tôi cách thực hiện nhiều yêu cầu cùng một lúc? Không đồng bộ nếu có thể. Tôi không biết nếu đó là những gì họ có nghĩa là với MultiCurl. Đồng bộ hóa cũng sẽ không phải là một vấn đề. Tôi chỉ muốn thực hiện nhiều yêu cầu cùng một lúc hoặc rất gần (khoảng thời gian ngắn).

+0

Có [bản trình diễn này] (http://guzzlephp.org/http-client/client.html#sending-requests-in-parallel) trong tài liệu. Đây vẫn là một cuộc gọi đồng bộ từ quan điểm của bạn, nhưng sẽ song song trong nội bộ - do đó tổng thời gian cho cuộc gọi sẽ chỉ là thời gian cho lần tìm kiếm dài nhất duy nhất. – halfer

Trả lời

18

Từ các tài liệu: http://guzzle3.readthedocs.org/http-client/client.html#sending-requests-in-parallel

Đối với một dễ sử dụng giải pháp mà trả về một hash của yêu cầu các đối tượng bản đồ để một phản ứng hoặc sai sót, xem http://guzzle3.readthedocs.org/batching/batching.html#batching

dụ viết tắt:

<?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

Nội dung cập nhật liên quan đến GuzzleHttp guzzlehttp/guzzle

Các cuộc gọi đồng thời/song song hiện được thực hiện thông qua một vài phương pháp khác nhau bao gồm cả Promises .. Concurrent Requests

Cách cũ để truyền mảng RequestInterfaces sẽ không hoạt động nữa.

Xem ví dụ đây

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

Cập nhật: Như đã đề cập trong ý kiến ​​và đề nghị bởi @ Sankalp-tambe, bạn cũng có thể sử dụng một cách tiếp cận khác nhau để tránh điều đó một tập hợp các yêu cầu đồng thời với một thất bại sẽ không trả lại tất cả các câu trả lời.

Mặc dù các tùy chọn được đề xuất với Hồ bơi là khả thi nhưng tôi vẫn thích lời hứa.

Một ví dụ với lời hứa là sử dụng các phương thức giải quyết và chờ đợi thay vì bỏ qua.

Sự khác biệt từ ví dụ trên sẽ là

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

Tôi đã tạo ra một ví dụ đầy đủ dưới đây để tham khảo về cách xử lý các phản ứng $ quá.

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 
} 

Mã ví dụ này ban đầu được đăng here.

+0

Mặc dù điều này rất phù hợp với trường hợp sử dụng của tôi khi tải nhiều dữ liệu URL của hình ảnh cùng một lúc, làm cách nào để xử lý tình huống trong đó một trong các URL được tải ném lỗi 404? Khi điều này xảy ra, Guzzle freaks ra và ném một ngoại lệ guzzle. Tôi không thể đảm bảo tính sẵn có của các URL nên tôi hy vọng chỉ tải nhiều yêu cầu và sử dụng các yêu cầu thực sự đi qua. – georaldc

+0

Nevermind, tôi chỉ làm lại mã của tôi để sử dụng GuzzleHttp \ Pool thay thế. Dường như cũng hoạt động tốt và cho tôi kiểm soát nhiều hơn một chút. – georaldc

+1

bạn có thể chia sẻ mã của mình cho nhiều url với Pool. –

Các vấn đề liên quan