Как обрабатывать асинхронные запросы GuzzleHTTP без блокировки? - PullRequest
0 голосов
/ 05 июля 2018

Мне нужно написать процессор, который потенциально может отправлять множество HTTP-запросов во внешнюю службу. Поскольку я хочу максимизировать производительность, я хочу минимизировать блокировку. Я использую PHP 5.6 и GuzzleHTTP.

GuzzleHTTP имеет опцию для асинхронных запросов. Но так как у нас есть только 1 поток, доступный в PHP, мне нужно выделить некоторое время для их обработки. К сожалению, я вижу только один способ сделать это - вызвать wait, который блокирует, пока все запросы не будут обработаны. Это не то, что я хочу.

Вместо этого я хотел бы иметь какой-то метод, который обрабатывает все, что прибыл, а затем возвращает. Так что я могу сделать что-то вроде:

$allRequests = [];

while ( !checkIfNeedToEnd() ) {
    $newItems = getItemsFromQueue();
    $allRequests = $allRequests + spawnRequests($newItems);
    GuzzleHttp::processWhatYouCan($allRequests);
    removeProcessedRequests($allRequests);
}

Возможно ли это?

1 Ответ

0 голосов
/ 05 июля 2018

Хорошо ... разобрался сам:

$handler = new \GuzzleHttp\Handler\CurlMultiHandler();
$client = new \GuzzleHttp\Client(['handler' => $handler]);
$promise1 = $client->getAsync("http://www.stackoverflow.com");
$promise2 = $client->getAsync("http://localhost/");

$doneCount = 0;

$promise1->then(function() use(&$doneCount) {
    $doneCount++;
    echo 'Promise 1 done!';
});
$promise2->then(function() use(&$doneCount) {
    $doneCount++;
    echo 'Promise 2 done!';
});

$last = microtime(true);
while ( $doneCount < 2 ) {
    $now = microtime(true);
    $delta = round(($now-$last)*1000);
    echo "tick($delta) ";
    $last = $now;

    $handler->tick();
}

И вывод, который я получаю:

тик (0) тик (6) тик (1) тик (0) тик (1001) тик (10) тик (96) Обещание 2 выполнено! Тик (97) Обещание 1 выполнено!

Волшебный ингредиент - создать CurlMultiHandler yoursef и затем вызвать tick(), когда это будет удобно. После этого обещания как обычно. И если очередь пуста, tick() немедленно возвращается.

Обратите внимание, что он все еще может блокироваться на срок до 1 секунды (по умолчанию), если нет активности. Это также может быть изменено при необходимости:

$handler = new \GuzzleHttp\Handler\CurlMultiHandler(['select_timeout' => 0.5]);

Значение указывается в секундах, но с плавающей запятой.

...