× 警告!旧版文档已经暂停维护,请查看新版文档。点击前往新版文档

子协程+通道

除了只用底层内置的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发送响应结果

  • 穆白

    这个地方没有弄明白. $serv->on('request',function(){}); 这个也是协程来操作的吗, 我的理解这个地方化是一个进程(worker) 来进行处理, 谁理解了.可否指点一二.

  • Sin

    在controller中如何使用协程?能否给一个例子????

  • 落落

    @穆白 看了版本更新记录,才发现在 4 版本以后,每个请求是由一个 Worker 来处理的(这点和 2 一样),但是每个请求的 onRequest 都是放在单独的协程里来处理的。每个请求的业务逻辑都开一个协程来处理,性能提升很大。

  • 消逝

    $result+=那里应该是[]=吧?例子好多都有问题

  • 消逝

    如果在$cli->get('/index.php'); 对应的接口index.php中sleep(2000)后再返回,返回值为啥为空?

  • 569284473a

    $result+=是正确的,数组相加和数组合并的机制不一样

  • crazy runner

    $resp->end(json_encode($result));这个有问题,var_dump(json_encode($result))为false,strlen(json_encode($result)) 结果为0,直接蒙B了,哈哈

  • 18301497790

    $result += $chan->pop(); 操作符不正确

  •  Static 

    和go语言的通道挺像的,但是setDefer机制和这个子协程+通道有什么区别?