子协程+通道
除了只用底层内置的setDefer机制实现并发请求之外,还可以使用子协程+通道实现并发。
使用实例
$serv = new \swoole_http_server("127.0.0.1", 9503, SWOOLE_BASE);$serv->on('request', function ($req, $resp) {$chan = new chan(2);go(function () use ($chan) {$cli = new Swoole\Coroutine\Http\Client('www.qq.com', 80);$cli->set(['timeout' => 10]);$cli->setHeaders(['Host' => "www.qq.com","User-Agent" => 'Chrome/49.0.2587.3','Accept' => 'text/html,application/xhtml+xml,application/xml','Accept-Encoding' => 'gzip',]);$ret = $cli->get('/');$chan->push(['www.qq.com' => $cli->body]);});go(function () use ($chan) {$cli = new Swoole\Coroutine\Http\Client('www.163.com', 80);$cli->set(['timeout' => 10]);$cli->setHeaders(['Host' => "www.163.com","User-Agent" => 'Chrome/49.0.2587.3','Accept' => 'text/html,application/xhtml+xml,application/xml','Accept-Encoding' => 'gzip',]);$ret = $cli->get('/');$chan->push(['www.163.com' => $cli->body]);});$result = [];for ($i = 0; $i < 2; $i++){$result += $chan->pop();}$resp->end(json_encode($result));});$serv->start();
实现原理
- 在
onRequest中需要并发两个http请求,可使用go函数创建2个子协程,并发地请求多个URL - 并创建了一个
chan,使用use闭包引用语法,传递给子协程 - 主协程循环调用
chan->pop,等待子协程完成任务,yield进入挂起状态 - 并发的两个子协程其中某个完成请求时,调用
chan->push将数据推送给主协程 - 子协程完成
URL请求后退出,主协程从挂起状态中恢复,继续向下执行调用$resp->end发送响应结果
