我是这么理解协程yield异步IO的

我是这么理解协程yield异步IO的

今天又仔仔细细的研究了一下鸟哥写的yield的文章: 传送门

突然对yield的作用明晰了。

就像很多人说的 yield 其实就是实现一种以同步方式写异步代码的功能,写了这么多年PHP,完全不清楚这个到底是啥意思。不过看完这篇文章算是懂了。

一般的PHP代码(类似于同步IO):

1.jpg

PHP完全以同步的方式在处理 从 【PHP处理】 -> 【处理完成】的这个过程。因为毕竟一次处理一个请求。

如果使用yield就完全不一样了(首先我们就不能用php-fpm了),php需要自己控制处理所有socket才能达到真异步。

例,一个业务逻辑(普通的):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$data = DB::select();

$respA = $httpClient->post($uri, $data);

if ($respA['code'] == 0) {
    $id = DB::insert($respA['data']);
    $respB = $httpClient->post($uri, ['some_id' => $id]);
}

return response()->ok();

如果我们用yield:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$data = yield AsyncDB::select();

$respA = yield $AsyncHttpClient->post($uri, $data);

if ($respA['code'] == 0) {
    $id = yield AsyncDB::insert($respA['data']);
    $respB = yield $AsyncHttpClient->post($uri, ['some_id' => $id]);
}

return response()->ok();

之前我一直很困惑,这么写有什么用呢?看了很多文章,甚至写了很多例子,都发现IO依然是同步的。

这是因为,我们想用到真正的yield的功能就要整个环境(框架)都支持它。

OK,详细来描述一下这段业务逻辑背后的事情:

2.jpg

上图只是说一次请求。

IO任务调度器是全局的,我们有成千上万个这种请求在处理:

3.jpg

IO任务调度器的设计就像是epoll 或者 select 一样,非阻塞(同步或者异步)。只要有IO完成了,协程就会返回到这个IO当时yield的地方,继续执行(就像设置断点一样)。

最后总结:

在有协程的框架设计中任务调度器的设计就是提高程序性能的关键,假如普通的同步请求一个单位时间处理1一个请求,那么这种yeild协程就是看机器的性能了。