Golang的并发调度:
1.协程调度器与线程池的区别:
1)如果线程池中某任务发生系统调用,操作系统会将该线程设为阻塞状态,则线程池中消费任务队列的线程变少了,消费任务的能力变弱了;
2)如果增加线程池中线程的数量,过多线程争抢CPU资源,线程上下文切换次数频繁,反而增加了系统负担,出现消费能力下降的情况;
3)协程调度器把阻塞的协程调度出线程,避免线程的频繁切换,达到使用少量线程实现高并发的效果。
2.协程调度器:
工作线程(M):由操作系统调度(稍大于P的个数);
处理器(P): 运行协程的必要资源,有调度协程的能力(默认情况下等于CPU核数,使用runtime.GOMAXPROCS()设置);
协程(G)。
1)M必须持有P才能执行;
2)每个处理器P有个运行队列,此外还有个全局运行队列——供多个处理器共享(处理器调度前需要加锁);处理器中协程创建的协程加入本地运行队列,如果本地运行队列满了或者阻塞的协程被唤醒,则加入全局运行队列,处理器除了调度本地协程,还会周期性地从全局运行队列中取协程调度;
3)调度:
(1)处理器依次将运行队列中协程调度到M中执行;
(2)多出来的M会在G产生系统调用时发挥作用(M池,与线程池类似);
(3)当G即将进入系统调用时,M将释放P,多出来的M获取P,继续执行P中G;
(4)当G结束系统调用时,要么获取一个P,继续执行G;要么放入全局队列,等待被P调度;
(5)如果一个G执行时间过长且有其他G在等待,会把该G暂停,转而调度其他G,达到时间片轮询的效果。