Как выполнить несколько запросов на поглощение одновременно?


Я могу выполнять одиночные запросы с помощью Guzzle, и я очень доволен производительностью Guzzle до сих пор, однако я прочитал в API Guzzle кое-что о мультициклах и пакетной обработке.

Не мог бы кто-нибудь объяснить мне, как делать несколько запросов одновременно? Асинхронный, если это возможно. Я не знаю, это ли то, что они подразумевают под мультициклом. Синхронизация также не будет проблемой. Я просто хочу выполнить несколько запросов одновременно или очень близко (короткий промежуток времени).

Author: halfer, 2013-10-22

2 answers

Из документов: 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')
));
 21
Author: Michael Dowling, 2015-07-21 13:50:58

Обновление, связанное с новым GuzzleHttp guzzlehttp/жрать

Параллельные/параллельные вызовы теперь выполняются несколькими различными методами, включая обещания.. Одновременные запросы

Старый способ передачи массива интерфейсов запросов больше не будет работать.

Смотрите пример здесь

    $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, вы также можете использовать другой подход, чтобы избежать того, что набор одновременный запрос с ошибкой не вернет все ответы.

Хотя варианты, предложенные с пулом, выполнимы, я все же предпочитаю обещания.

Пример с обещаниями - использовать методы расчета и ожидания вместо разворачивания.

Отличие от приведенного выше примера будет заключаться в

$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
}

Этот пример кода был первоначально опубликован здесь.

 18
Author: Bizmate, 2017-03-09 06:50:30