Как выполнять несколько запросов Guzzle одновременно?
Я могу выполнять одиночные запросы с помощью Guzzle, и пока я очень доволен показателем Guzzle, я прочитал в API Guzzle что-то о MultiCurl и Batching.
Может кто-нибудь объяснить мне, как делать несколько запросов одновременно? Async если возможно. Я не знаю, что это значит с MultiCurl. Синхронизация также не будет проблемой. Я просто хочу делать несколько запросов одновременно или очень близко (короткое время).
Ответы
Ответ 1
Из документов:
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')
));
Ответ 2
Обновление, связанное с новым GuzzleHttp guzzlehttp/guzzle
Параллельные вызовы теперь выполняются несколькими различными способами, включая Promises.. Параллельные запросы
Старый способ передачи массива 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, вы также можете использовать другой подход, чтобы избежать того, что набор одновременных запросов с отказом не будет возвращать все ответы.
В то время как варианты, предлагаемые с пулом, возможны, я все же предпочитаю Promises.
Пример с promises заключается в том, чтобы использовать методы расчета и ожидания вместо разворота.
Отличие от приведенного выше примера будет
$responses = \GuzzleHttp\Promise\settle($requestArr)->wait();
Я создал полный пример ниже для справки о том, как обрабатывать $response тоже.
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
}
Этот примерный код был первоначально опубликован здесь.