协程(CoRoutine)是一种轻量级的用户态线程。简单来说,线程(thread)的调度是由操作系统负责,线程的睡眠、等待、唤醒的时机是由操作系统控制,开发者无法决定。使用协程,开发者可以自行控制程序切换的时机,可以在一个函数执行到一半的时候中断执行,让出CPU,在需要的时候再回到中断点继续执行。因为切换的时机是由开发者来决定的,就可以结合业务的需求来实现一些高级的特性。
协程的特点:
有独立的栈空间
共享程序堆空间
调度由用户控制
协程是轻量级的线程
协程的优点:
代码编辑简单。可以将异步处理逻辑代码用同步的方式编写,将多个异步操作集中到一个函数中完成。
单线程模式,没有线程安全的问题,不需要加锁操作。
性能好。协程是用户态线程,切换更加高效。
为什么协程比线程轻量?
一旦创建完线程,你就无法决定他什么时候获得时间片,什么时候让出时间片了,你把它交给了内核。而协程编写者可以有:可控的切换时机和很小的切换代价。从操作系统有没有调度权上看,协程就是因为不需要进行内核态的切换。
go协程调用跟切换比线程效率高
线程并发执行流程:
线程是内核对外提供的服务,应用程序可以通过系统调用让内核启动线程,由内核来负责线程调度和切换。线程在等待IO操作时线程变为unrunnable状态会触发上下文切换。现代操作系统一般都采用抢占式调度,上下文切换一般发生在时钟中断和系统调用返回前,调度器计算当前线程的时间片,如果需要切换就从运行队列中选出一个目标线程,保存当前线程的环境,并且恢复目标线程的运行环境,最典型的就是切换ESP指向目标线程内核堆栈,将EIP指向目标线程上次被调度出时的指令地址。
go协程并发执行流程:
不依赖操作系统和其提供的线程,golang自己实现的CSP并发模型实现:M, P, G。
go协程也叫用户态线程,协程之间的切换发生在用户态。在用户态没有时钟中断,系统调用等机制,因此效率高。
go协程占用内存少
执行go协程只需要极少的栈内存(最新版默认2KB,可以根据程序执行自动伸缩),默认情况下,线程栈的大小为1MB。
goroutine就是一段代码,一个函数入口,以及在堆上为其分配的一个堆栈。所以它非常廉价,我们可以很轻松的创建上万个goroutine,但它们并不是被操作系统所调度执行。