关于Curl在Swoole协程中的解决方案详析
前言
众所周知,在Swoole应用中,是不推荐使用Curl的,因为Curl会阻塞进程。
本文会用实际的代码和数据,用最直观的方式,让你明白为什么。
最后还会给出Curl在Swoole中的解决方案,如果不想看分析可以直接拉到最后。
例程对比
宇润看文章不喜欢那些虚的,所以自己写也比较实在,直接来跑一下代码,用数据看为什么不推荐在Swoole使用Curl。
为了偷懒,我直接用了YurunHttp的Curl和SwooleHandler,来替代那些又臭又长的Curl代码。
代码
composer.json
{ "require":{ "yurunsoft/yurun-http":"~3.0" } }
server.php
on('workerstart',function(){ \Swoole\Runtime::enableCoroutine(); }); $http->on('request',function($request,$response){ sleep(1);//假设各种处理耗时1秒 $response->end($request->get['id'].':'.date('Y-m-dH:i:s')); }); $http->start();
test.php
get('http://127.0.0.1:9501/?id='.$i);//请求地址 var_dump($response->body()); $channel->push(1); }); } for($i=0;$ipop(); } $channel->close(); echo'coroutinehttpclienttime:',(microtime(true)-$time).'s',PHP_EOL,PHP_EOL; //curl echo'curl:',PHP_EOL,PHP_EOL; $time=microtime(true); YurunHttp::setDefaultHandler(\Yurun\Util\YurunHttp\Handler\Curl::class);//切换为CurlHandler $channel=new\Swoole\Coroutine\Channel; for($i=0;$i get('http://127.0.0.1:9501/?id='.$i);//请求地址 var_dump($response->body()); $channel->push(1); }); } for($i=0;$i pop(); } $channel->close(); echo'curltime:',(microtime(true)-$time).'s',PHP_EOL,PHP_EOL; });
运行
首次运行需要执行composerupdate安装依赖
运行phpserver.php,启动服务端
运行phptest.php,启动客户端
运行结果
coroutinehttpclient:
string(22)"1:2019-09-1108:35:54"
string(22)"0:2019-09-1108:35:54"
string(22)"2:2019-09-1108:35:54"
coroutinehttpclienttime:1.0845630168915scurl:
string(22)"0:2019-09-1108:35:55"
string(22)"1:2019-09-1108:35:56"
string(22)"2:2019-09-1108:35:57"
curltime:3.0139901638031s
结果分析
上面的代码在服务端延迟1秒后返回结果,模拟实际业务的耗时。
通过客户端的耗时可以看出,Curl3次请求总共耗时3秒多,而协程客户端仅耗时1秒多。
因为前一次请求中,Curl等待返回内容的时间是干不了其他事情的。而协程客户端等待返回内容期间,是挂起当前协程,转而再去执行其它协程中的代码。
解决方案
CoroutineHttpClient
使用Swoole内置的协程客户端实现,适合有一定基础的开发者使用。
文档:https://wiki.swoole.com/wiki/...
Guzzle-Swoole
我们在项目中,可能很少直接写curl,但是用到的很多第三方类库(如某某云们的SDK)会有用到。
这些第三方类库通常使用的是Guzzle作为Http客户端,而Guzzle底层也是使用Curl实现。
宇润专为此种场景研发了Guzzle-Swoole包,引入后可以让这些SDK轻松支持协程,而不用修改一行代码。
使用方法
执行命令直接安装依赖:composerrequireyurunsoft/guzzle-swoole~1.1
全局设定处理器:
request('GET','http://www.baidu.com',[ 'verify'=>false, ]); var_dump($response->getStatusCode()); });
手动指定Swoole处理器:
useGuzzleHttp\Client; useGuzzleHttp\HandlerStack; useYurun\Util\Swoole\Guzzle\SwooleHandler; go(function(){ $handler=newSwooleHandler(); $stack=HandlerStack::create($handler); $client=newClient(['handler'=>$stack]); $response=$client->request('GET','http://www.baidu.com',[ 'verify'=>false, ]); var_dump($response->getBody()->__toString(),$response->getHeaders()); });
YurunHttp
YurunHttp是开源的PHPHTTP类库,支持链式操作,简单易用。
支持所有常见的GET、POST、PUT、DELETE、UPDATE等请求方式,支持浏览器级别Cookies管理、上传下载、设置和读取header、Cookie、请求参数、失败重试、限速、代理、证书等。
3.0版完美支持Curl、Swoole协程;3.2版支持SwooleWebSocket客户端。
使用方法
执行命令直接安装依赖:composerrequireyurunsoft/yurun-http~3.2
get('http://www.baidu.com'); echo'html:',PHP_EOL,$response->body(); }
截止发稿时,Swoole4.4新增的hookCurl依然是实验性功能。虽然宇润曾为该功能贡献过一部分代码,但是由于需要兼容的工作量非常大,有太多OPTION不被支持,我个人是暂时不推荐使用hookCurl的。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对毛票票的支持。