golang中的GPM(用户态的线程池)
- 全局队列(Global Queue):存放等待运行的 G。
- P 的本地队列:同全局队列类似,存放的也是等待运行的 G,存的数量有限,不超过 256 个。新建 G’时,G’优先加入到 P 的本地队列,如果队列满了,则会把本地队列中一半的 G 移动到全局队列。
- P 列表:所有的 P 都在程序启动时创建,并保存在数组中,最多有 GOMAXPROCS(可配置) 个。
- M:线程想运行任务就得获取 P,从 P 的本地队列获取 G,P 队列为空时,M 也会尝试从全局队列拿一批 G 放到 P 的本地队列,或从其他 P 的本地队列偷一半放到自己 P 的本地队列。M 运行 G,G 执行之后,M 会从 P 获取下一个 G,不断重复下去。
GO和C#的区别在于,GO将池化数据作用于用户空间,一个线程就是一个所谓的“核心”,C#将池化的数据作用于内核空间,一个进程中只有一个唯一的线程池,一个线程就是内核的一个核心。在go中切换线程是所谓切换用户态保存的上下文,C#中切换线程时需要切换内核中的上下文和数据的上下文。相同之处:一个线程可以作用于不同的任务。
go中的线程池: