前言
在传统PHP的LNMP架构下,有些问题始终困扰着我们,由于PHP程序只能串行执行的特性,在IO密集型应用下,PHP程序只能在IO操作完成后才能执行后续的代码,其中有大部分时间都在等待IO,严重影响执行效率,这是非常不合理。现在有这样一个场景,一个接口需要调用10个第三方的Http接口才能拿到所有数据,假设每个接口调用平均耗时300ms,在传统PHP的串行模式下,需要3秒才能执行完。使用基于Swoole的协程Http客户端可以解决这个问题,实现Http请求的并发调用。
实践
下面我们使用传统Http客户端
和Swoole协程客户端
做对比,对比方式为,通过连续N次请求淘宝首页,对比请求总响应时间,就能够直观看到并发调用的优势。
传统Http客户端示例
$start = microtime(true);
$n = 50;
for ($i = 0; $i < $n; $i++) {
$http = new Http();
$res = $http->get('https://www.taobao.com/');
$res->getBody()->getContents();
}
$end = microtime(true);
echo bcsub($end,$start,2).PHP_EOL;
Swoole协程Http客户端示例
go(function (){
$start = microtime(true);
//并发请求 n
$result = [];
$clients = [];
$n = 50;
for ($i = 0; $i < $n; $i++) {
$cli = new \Swoole\Coroutine\Http\Client('www.taobao.com', 443,true);
$cli->setHeaders([
'Host' => "www.taobao.com",
"User-Agent" => 'Chrome/49.0.2587.3',
'Accept' => 'text/html,application/xhtml+xml,application/xml',
'Accept-Encoding' => 'gzip',
]);
$cli->set(['timeout' => 2]);
$cli->setDefer();
$cli->get('/');
$clients[] = $cli;
}
for ($i = 0; $i < $n; $i++) {
if (!$clients[$i]->recv()) {
continue;
}
$result[] = $clients[$i]->body;
}
$end = microtime(true);
echo bcsub($end,$start,2).PHP_EOL;
});
数据分析
调用次数 | 响应时间(协程) | 响应时间(传统) |
---|---|---|
10 | 1.09s | 3.64s |
20 | 2.33s | 7.27s |
30 | 2.89s | 14.91s |
50 | 3.96s | 17.57s |
100 | 7.33s | 37.23s |
通过上面的数据可以看到,协程模式速度是传统模式的好几倍,而且随着调用次数增多,协程模式的速度优势越来越明显,这就IO密集型场景下,异步模式带来的巨大性能提升。
串行调用、并发调用 图解
总结
如果大家和我一样,在IO密集型场景下,程序的速度到了瓶颈,无论怎么优化,速度都没有质的提升,那么可以尝试使用Swoole的协程模式,可能会带来意想不到的效果。在大多数Web场景下,并不是我们的程序执行慢,而是大多数时间都在等待IO结束,无论怎么优化代码提升都不明显,不如换个思路,使用协程异步来解决IO等待问题,带来的提升是巨大的。希望本篇文章对你有帮助!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。