线程由系统调度,协程由运行时调度
而为什么协程可以做到同时创建上万个,是因为go的协程初始化资源是4KB空间,比线程轻量级。
区别在于
1. 一个线程可以多个协程,一个进程也可以单独拥有多个协程。
2. 线程进程都是同步机制,而协程则是异步。
3. 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。
4. 线程是抢占式,而协程是非抢占式的,所以需要用户自己释放使用权来切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力。
5. 协程并不是取代线程, 而且抽象于线程之上, 线程是被分割的CPU资源, 协程是组织好的代码流程, 协程需要线程来承载运行, 线程是协程的资源, 但协程不会直接使用线程, 协程直接利用的是执行器(Interceptor), 执行器可以关联任意线程或线程池, 可以使当前线程, UI线程, 或新建新程.。
6. 线程是协程的资源。协程通过Interceptor来间接使用线程这个资源。
协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:
* 无需线程上下文切换的开销
* 无需原子操作锁定及同步的开销
* 方便切换控制流,简化编程模型
**缺点:**
无法利用多核资源:协程的本质是个单线程,它不能同时将 多个CPU用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序
**最佳实践**
* 线程和协程推荐在IO密集型的任务(比如网络调用)中使用,而在CPU密集型的任务中,表现较差。
* 对于CPU密集型的任务,则需要多个进程,绕开GIL的限制,利用所有可用的CPU核心,提高效率。
* 所以大并发下的最佳实践就是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。