# 使用协程的优势 Swoole是高性能异步框架,正因为异步所以高性能,但是异步也有异步的不好,写逻辑代码有时候就非常的不方便,需要多层嵌套回调,弄得代码的可读性很差维护起来非常的不方便,那么如何解决这个弊端呢?那就是使用协程。 SwooleDistributed框架提供了一套基于yield关键字的协程写法。 #回调风格和协程风格的区别 举例说明: 回调风格: ```php /** * mysql 测试 * @throws \Server\CoreBase\SwooleException */ public function mysql_test() { $this->mysql_pool->dbQueryBuilder->select('*')->from('account')->where('sex', 1); $this->mysql_pool->query(function ($result) { print_r($result); $this->destroy(); }); } ``` 协程风格: ```php /** * mysql 测试 * @throws \Server\CoreBase\SwooleException */ public function mysql_test() { $mySqlCoroutine = $this->mysql_pool->dbQueryBuilder->select('*')->from('account')->where('sex', 1)->coroutineSend(); $result = yield $mySqlCoroutine; print_r($result); $this->destroy(); } ``` 上述代码还只是基础,想想看多次请求并且依赖的情况 回调风格: ```php public function test($callback) { $this->redis_pool->get('test',function ($uid)use($callback){ $this->mysql_pool->dbQueryBuilder->select('*')->from('account')->where('uid', $uid); $this->mysql_pool->query(function ($result)use($callback) { call_user_func($callback,$result); }); }); } ``` 协程风格: ```php public function test() { $redisCoroutine = $this->redis_pool->getCoroutine()->get('test'); $uid = yield $redisCoroutine; $mySqlCoroutine = $this->mysql_pool->dbQueryBuilder->select('*')->from('account')->where('uid', $uid)->coroutineSend(); $result = yield $mySqlCoroutine; return $result; } ``` 上面的代码是在一个model中,按照以往的回调风格,controller调用这个model还需要传进去一个回调函数才能获取到值(我觉得这么做的人一定会疯),而协程风格你只需要按部就班的return结果就行了。和同步的代码唯一的区别就是多了一个yield关键字。 好了我们再看调用这个model的controller怎么写。 回调风格: ```php /** * 非协程测试 */ public function http_testNOCoroutine() { $this->testModel = $this->loader->model('TestModel', $this); $this->testModel->test(function($result){ $this->http_output->end($result); }); } ``` 协程风格: ```php /** * 协程测试 */ public function http_testCoroutine() { $this->testModel = $this->loader->model('TestModel', $this); $result = yield $this->testModel->test(); $this->http_output->end($result); } ``` 同样只是要多加一个yield关键字。是不是很方便~,注意只有这个model的方法内使用了yield,控制器调用的时候才需要加yield关键字。普通的方法是不需要的,当然你加了也不会报错。 # 协程中的异常? swooleDistributed框架已经将协程的使用变得很方便了,至于异常和平常的写法一毛一样。 ```php public function test_exceptionII() { $mySqlCoroutine = $this->mysql_pool->dbQueryBuilder->select('*')->from('account')->where('uid', 10303)->coroutineSend(); $result = yield $mySqlCoroutine; throw new \Exception('test'); } ``` 无论你是在model中还是在controller中,还是在model的model中。。。。 总之throw出来就行,上一层使用try可以捕获到错误。 这里还有个小小的体验优化,当报错一直到controller层的时候,会被controller的onExceptionHandle捕获到,你可以重写这个函数实现异常情况下的客户端回复。 # 协程的嵌套 支持无限级的嵌套。 # 协程的调度顺序 调节yield的位置即可调节接收的顺序。 ```php $redisCoroutine = $this->redis_pool->getCoroutine()->get('test'); $uid = yield $redisCoroutine; $mySqlCoroutine = $this->mysql_pool->dbQueryBuilder->select('*')->from('account')->where('uid', $uid)->coroutineSend(); $result = yield $mySqlCoroutine; ``` 上面的代码调度顺序是redis_send->redis_rev->mysql_send->mysql_rev。 ```php $redisCoroutine = $this->redis_pool->getCoroutine()->get('test'); $mySqlCoroutine = $this->mysql_pool->dbQueryBuilder->select('*')->from('account')->where('uid', 123)->coroutineSend(); $uid = yield $redisCoroutine; $result = yield $mySqlCoroutine; ``` 上面的代码调度顺序是redis_send->mysql_send->redis_rev->mysql_rev。