子协程+通道

除了只用底层内置的setDefer机制实现并发请求之外,还可以使用子协程+通道实现并发。

使用实例

  1. $serv = new \swoole_http_server("127.0.0.1", 9503, SWOOLE_BASE);
  2. $serv->on('request', function ($req, $resp) {
  3. $chan = new chan(2);
  4. go(function () use ($chan) {
  5. $cli = new Swoole\Coroutine\Http\Client('www.qq.com', 80);
  6. $cli->set(['timeout' => 10]);
  7. $cli->setHeaders([
  8. 'Host' => "www.qq.com",
  9. "User-Agent" => 'Chrome/49.0.2587.3',
  10. 'Accept' => 'text/html,application/xhtml+xml,application/xml',
  11. 'Accept-Encoding' => 'gzip',
  12. ]);
  13. $ret = $cli->get('/');
  14. $chan->push(['www.qq.com' => $cli->body]);
  15. });
  16. go(function () use ($chan) {
  17. $cli = new Swoole\Coroutine\Http\Client('www.163.com', 80);
  18. $cli->set(['timeout' => 10]);
  19. $cli->setHeaders([
  20. 'Host' => "www.163.com",
  21. "User-Agent" => 'Chrome/49.0.2587.3',
  22. 'Accept' => 'text/html,application/xhtml+xml,application/xml',
  23. 'Accept-Encoding' => 'gzip',
  24. ]);
  25. $ret = $cli->get('/');
  26. $chan->push(['www.163.com' => $cli->body]);
  27. });
  28. $result = [];
  29. for ($i = 0; $i < 2; $i++)
  30. {
  31. $result += $chan->pop();
  32. }
  33. $resp->end(json_encode($result));
  34. });
  35. $serv->start();

实现原理

  • onRequest中需要并发两个http请求,可使用go函数创建2个子协程,并发地请求多个URL
  • 并创建了一个chan,使用use闭包引用语法,传递给子协程
  • 主协程循环调用chan->pop,等待子协程完成任务,yield进入挂起状态
  • 并发的两个子协程其中某个完成请求时,调用chan->push将数据推送给主协程
  • 子协程完成URL请求后退出,主协程从挂起状态中恢复,继续向下执行调用$resp->end发送响应结果