问题
我们正在尝试使用guzzle进行并发异步请求。经过这样的资源(这样)之后,我们提出了下面共享的一些代码。但是,它无法正常工作。
看起来Guzzle是同步执行这些请求的,而不是异步。
期望
仅出于测试目的,我们正在击中一个内部URL,该URL可以进行5秒的睡眠。以10的并发性为10其中几乎将同时完成。这将使Guzzle Client从迭代器中获取10个新请求,依此类推。
代码
$iterator = function() {
$index = 0;
while (true) {
$client = new Client(['timeout'=>20]);
$url = 'http://localhost/wait/5' . $index++;
$request = new Request('GET',$url, []);
echo "Queuing $url @ " . (new Carbon())->format('Y-m-d H:i:s') . PHP_EOL;
yield $client
->sendAsync($request)
->then(function(Response $response) use ($request) {
return [$request, $response];
});
}
};
$promise = GuzzleHttpPromiseeach_limit(
$iterator(),
10, /// concurrency,
function($result, $index) {
/** GuzzleHttpPsr7Request $request */
list($request, $response) = $result;
echo (string) $request->getUri() . ' completed '.PHP_EOL;
},
function(RequestException $reason, $index) {
// left empty for brevity
}
);
$promise->wait();
实际结果
我们发现,直到第一个请求完成之前,该Guzzle从未提出第二个请求。等等。
Queuing http://localhost/wait/5/1 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/2 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/3 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/4 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/5 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/6 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/7 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/8 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/9 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/10 @ 2017-09-01 17:15:28
http://localhost/wait/5/1 completed
Queuing http://localhost/wait/5/11 @ 2017-09-01 17:15:34
http://localhost/wait/5/2 completed
Queuing http://localhost/wait/5/12 @ 2017-09-01 17:15:39
http://localhost/wait/5/3 completed
Queuing http://localhost/wait/5/13 @ 2017-09-01 17:15:45
http://localhost/wait/5/4 completed
Queuing http://localhost/wait/5/14 @ 2017-09-01 17:15:50
OS/版本信息
- ubuntu
- php/7.1.3
- guzzlehttp/6.2.1
- curl/7.47.0
问题可能是 guzzlehttp promise enth_limit ..也许不能足够快地启动或解决承诺。我们可能必须将其欺骗到外部tick
。
在示例代码中,您正在为要提出的每个请求创建一个新的GuzzleHttpClient
实例。但是,这似乎并不重要,但是,在GuzzleHttpClient
的实例化过程中,如果没有提供,它将设置默认处理程序。(然后将此值传递给通过客户端发送的任何请求,除非被覆盖。)
注意:它决定了从此功能中使用的最佳处理程序。不过,它很可能最终会默认为curl_mutli_exec
。
这是什么重要性?这是负责同时跟踪和执行多个请求的基础处理程序。每次创建一个新处理程序,您的请求都没有正确地组成并汇总在一起。为了对此有更多的了解,请把gander纳入 curl_multi_exec
文档。
因此,您有两种处理方法:
通过客户端通过迭代器:
$client = new GuzzleHttpClient(['timeout' => 20]);
$iterator = function () use ($client) {
$index = 0;
while (true) {
if ($index === 10) {
break;
}
$url = 'http://localhost/wait/5/' . $index++;
$request = new Request('GET', $url, []);
echo "Queuing $url @ " . (new Carbon())->format('Y-m-d H:i:s') . PHP_EOL;
yield $client
->sendAsync($request)
->then(function (Response $response) use ($request) {
return [$request, $response];
});
}
};
$promise = GuzzleHttpPromiseeach_limit(
$iterator(),
10, /// concurrency,
function ($result, $index) {
/** @var GuzzleHttpPsr7Request $request */
list($request, $response) = $result;
echo (string)$request->getUri() . ' completed ' . PHP_EOL;
}
);
$promise->wait();
或在其他地方创建处理程序并将其传递给客户:(尽管我不确定您为什么要这样做,但是它在那里!)
)$handler = GuzzleHttpHandlerStack::create();
$iterator = function () use ($handler) {
$index = 0;
while (true) {
if ($index === 10) {
break;
}
$client = new Client(['timeout' => 20, 'handler' => $handler])
$url = 'http://localhost/wait/5/' . $index++;
$request = new Request('GET', $url, []);
echo "Queuing $url @ " . (new Carbon())->format('Y-m-d H:i:s') . PHP_EOL;
yield $client
->sendAsync($request)
->then(function (Response $response) use ($request) {
return [$request, $response];
});
}
};
$promise = GuzzleHttpPromiseeach_limit(
$iterator(),
10, /// concurrency,
function ($result, $index) {
/** @var GuzzleHttpPsr7Request $request */
list($request, $response) = $result;
echo (string)$request->getUri() . ' completed ' . PHP_EOL;
}
);
$promise->wait();