先了解下协程概念:
协程可以理解为纯用户态的线程,相对于进程与线程,协程的所有操作都可以在用户端完成,创建和切换的消耗更低。
相对于线程分时调度与抢占式调度,协程的调度是用户手动切换。调度策略是协作式调度。
再理解一下异步IO与协程的关联:
程序执行过程中,一部分使用cpu进行逻辑处理,另一部分进行IO传输。
同步IO中,等待数据传输完成,传输过程中线程阻塞,导致CPU等待闲置,也导致了资源浪费,是程序执行效率低下的主要原因。
最初,可使用多线程解决开启多个线程,一个管IO操作,一个管CPU操作。但是线程系统级的抢占式切换,成本较高,弊端明显。
这时,可引入异步IO。绑定一个回调函数,线程本身不用等待IO操作,内核数据准备好之后,直接回调。这就是异步IO。但也引入了编码困难的问题。
最后,引入协程概念。结合协程,遇到IO操作,就提交一个异步操作,将控制权交给另一个协程(这点类似多线程,而协程开销低,用户端切换调度,成本低)。
(在Swoole 4.x中,协程取代了异步回调,成为Swoole推荐的编程方式。Swoole协程解决了异步回调编程困难的问题,使用协程可以
已传统同步编程的方法编写代码,底层自动切换为异步IO,即保证了编程的简单性,又可以借助异步IO,提升系统的并发能力。)
对于IO操作密集的问题(比如高并发场景),可引入协程概念,效果明显客观。
Swoole 协程:
在Swoole 4.x中,协程取代了异步回调,成为Swoole推荐的编程方式。Swoole协程解决了异步回调编程困难的问题,使用协程可以
已传统同步编程的方法编写代码,底层自动切换为异步IO,即保证了编程的简单性,又可以借助异步IO,提升系统的并发能力。
在HTTP服务下示例:
基于Request回调的协程上下文,使用 MySQL协程客户端。
msyql->connect在执行IO操作时,保持当前信息(包括协程的状态,ZendVM上下文以及协程描述的信息),并让出程序控制权,
继续EventLoop机制处理客户端的Request。
与go协程的不同点:
1、协程客户端必须在协程环境中使用。
//申明一个协程环境。
go(function(){
Swoole\Coroutine\MySQL();
})
2、基于单线程,无法利用多核CPU,同意时间只有一个线程在调度。
go 协程:
goroutine是轻量级线程,Go语言从语言层面就支持原生协程。不需要申明协程环境。
线程必须指定堆栈大小,堆栈大小都是固定的。go协程堆栈开销只用2kb,可以根据程序需要增大和缩小。
goroutine通过GPM调度模型实现:
M:线程,一个M就是一个线程,goroutine跑在M之上。
G:goroutine,有自己的栈。
P:Processor处理器,主要用来执行goroutine,并且维护了一个goroutine队列。
Go 在 runtime、系统调用等多个方面对 goroutine 调度进行了封装和处理,当遇到长时间执行或进行系统调用时,
会主动把当前协程的 CPU 转让出去,让其他协程调度执行。
go协程基于多线程,可以利用多核CPU,同意时间有多个协程在执行调度。