前言
众所周知,在 Swoole 应用中,是不推荐使用 Curl 的,因为 Curl 会阻塞进程。
本文会用实际的代码和数据,用最直观的方式,让你明白为什么。
最后还会给出 Curl 在 Swoole 中的解决方案,如果不想看分析可以直接拉到最后。
例程对比
宇润看文章不喜欢那些虚的,所以自己写也比较实在,直接来跑一下代码,用数据看为什么不推荐在 Swoole 使用 Curl。
为了偷懒,我直接用了 YurunHttp 的 Curl 和 Swoole Handler,来替代那些又臭又长的 Curl 代码。
代码
composer.json
{ "require": { "yurunsoft/yurun-http": "~3.0" } }
server.php
<?php $http = new Swoole\Http\Server('127.0.0.1', 9501); $http->on('workerstart', function(){ \Swoole\Runtime::enableCoroutine(); }); $http->on('request', function ($request, $response) { sleep(1); // 假设各种处理耗时1秒 $response->end($request->get['id'] . ': ' . date('Y-m-d H:i:s')); }); $http->start();
test.php
<?php use Yurun\Util\YurunHttp; use Yurun\Util\HttpRequest; require __DIR__ . '/vendor/autoload.php'; define('REQUEST_COUNT', 3); go(function(){ // 协程客户端 echo 'coroutine http client:', PHP_EOL, PHP_EOL; $time = microtime(true); YurunHttp::setDefaultHandler(\Yurun\Util\YurunHttp\Handler\Swoole::class); // 切换为 Swoole Handler $channel = new \Swoole\Coroutine\Channel; for($i = 0; $i < REQUEST_COUNT; ++$i) { go(function() use($channel, $i){ $http = new HttpRequest; $response = $http->get('http://127.0.0.1:9501/?id=' . $i); // 请求地址 var_dump($response->body()); $channel->push(1); }); } for($i = 0; $i < REQUEST_COUNT; ++$i) { $channel->pop(); } $channel->close(); echo 'coroutine http client time: ', (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); // 切换为 Curl Handler $channel = new \Swoole\Coroutine\Channel; for($i = 0; $i < REQUEST_COUNT; ++$i) { go(function() use($channel, $i){ $http = new HttpRequest; $response = $http->get('http://127.0.0.1:9501/?id=' . $i); // 请求地址 var_dump($response->body()); $channel->push(1); }); } for($i = 0; $i < REQUEST_COUNT; ++$i) { $channel->pop(); } $channel->close(); echo 'curl time: ', (microtime(true) - $time) . 's', PHP_EOL, PHP_EOL; });
运行
首次运行需要执行 composer update 安装依赖