如何在不阻塞的情况下处理 GuzzleHTTP 异步请求?

Vil*_*lx- 3 php asynchronous guzzle

我需要编写一个可以向外部服务发送许多 HTTP 请求的处理器。由于我想最大限度地提高性能,因此我希望最大限度地减少阻塞。我正在使用 PHP 5.6 和 GuzzleHTTP。

GuzzleHTTP 确实有一个异步请求选项。但由于 PHP 中只有 1 个可用线程,我需要分配一些时间来处理它们。不幸的是,我只看到一种方法 - 调用waitwhich 块,直到所有请求都得到处理。那不是我想要的。

相反,我想要一些方法来处理已经到达的内容,然后返回。这样我就可以做一些类似的事情:

$allRequests = [];

while ( !checkIfNeedToEnd() ) {
    $newItems = getItemsFromQueue();
    $allRequests = $allRequests + spawnRequests($newItems);
    GuzzleHttp::processWhatYouCan($allRequests);
    removeProcessedRequests($allRequests);
}
Run Code Online (Sandbox Code Playgroud)

这可能吗?

Vil*_*lx- 6

好吧...我自己想出来了:

$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();
}
Run Code Online (Sandbox Code Playgroud)

我得到的输出是:

勾选(0) 勾选(6) 勾选(1) 勾选(0) 勾选(1001) 勾选(10) 勾选(96) 承诺2 完成!勾选(97) 承诺1 完成!

神奇的成分是创造CurlMultiHandler你自己,然后tick()在方便的时候召唤它。之后就如往常一样许诺了。如果队列为空,则tick()立即返回。

请注意,如果没有活动,它仍然可以阻塞最多 1 秒(默认)。如果需要,也可以更改:

$handler = new \GuzzleHttp\Handler\CurlMultiHandler(['select_timeout' => 0.5]);
Run Code Online (Sandbox Code Playgroud)

该值以秒为单位,但具有浮点数。