协程
- 进程的概念:是资源调度的基本单位,是应用程序的启动实例,每个进程都有独立的内存空间,不同进程通过进程间的通信方式来通信。(方式有管道pipe、命名管道FIFO、消息队列MQ、信号量semaphore、共享内存shared memory、信号signal、内存映射mapped memory和Socket)
- 线程的概念:是程序执行的基本单位,线程从属于进程,每个进程至少包含一个线程,线程是CPU调度的基本单位,多个线程之间可以共享进程的资源并通过线程间的通信方式来通信。(方式有信号、锁机制、条件变量和信号量)
- 协程的概念:用户态的轻量级线程,线程内部调度的基本单位,协程不受操作系统调度,协程调度器由用户应用程序提供,协程调度器按照调度策略将协程调度到线程中运行。
- Go应用程序中的协程调度器由runtime包提供,用户使用go关键字即可创建协程,在语言层面直接支持协程。
协程的优势
相对于线程的好处:
- 减少线程切换的成本
- 因为协程只存在于一个线程之中,不需要多线程之间的锁机制
- 协程更加轻量化,创建一个线程约1M,协程只需要几k或者几十k
- 在高并发应用中,为了避免造成不必要的开销,会引入线程池技术。
在线程池中预先保存一定数量的线程,新任务不会以创建新线程的方式去执行,而是将任务发布到任务队列中,线程池中的线程不断从任务队列中取出任务并执行,这样可以有效地减少频繁创建和销毁线程带来的开销。
线程池中的worker线程不断从任务队列中取出任务并执行,worker线程交给操作系统进行调度。
问题来了,如果worker线程执行的任务中发生系统调用,操作系统会把该线程设置为阻塞状态,也就是说这个worker线程不work了,也就导致线程池中可以消费任务的worker线程变少了,消费能力也就变差了。
此时需要重新审视线程池中线程的数量,但是线程池中增加太多的线程会出现争抢CPU资源,从而遇到瓶颈。
过多的线程也会增加上下文切换的开销,而工作在用户态下的协程能够大大减少上下文切换来带的开销。
协程调度器将可运行的协程逐个调度到线程中执行,同时将阻塞的协程调度出线程,从而有效避免线程的频繁切换,达到使用少量线程实现高并发的效果。