Golang-100-Days/Day16-20(Go语言基础进阶)/day17_Go语言并发Goroutine.md at master · rubyhan1314/Golang-100-Days · GitHub
第2讲-调度器的由来和分析_哔哩哔哩_bilibili
一个进程最多可以创建多少个线程?-CSDN博客
引入协程
go语言中内置了协程goroutine;可以简单理解:协程是轻量级的线程,线程是轻量级的进程。
在Linux的32位操作系统中,创建一个进程需要4G的虚拟内存,创建一个线程需要8MB的虚拟内存。频繁的创建线程会占用内存资源。
如果是一个单核cpu,在多个线程中来回切换并不是无缝切换:首先cpu把线程A运行的数据从cpu寄存器移动到内存中,这个过程需要时间和内存资源,然后再运行线程B,同样的需要将运行的线程B数据移动到内存。这样的并发效率并不高。
引入协程,就是为了提高并发效率,减少内存消耗。
实现协程
1)线程绑定
cpu处理内核空间中的线程,用户空间中的用户线程去绑定内核空间的内核线程。
1个用户线程对应1个内核线程,线程是这样的1对1关系
2)P调度器
go语言初始的调度器实现的是n对1的关系,但是一个协程阻塞,其他协程无法运行。
3)gmp模型思想
go语言后来实现的是n:m的多对多关系,未被阻塞的协程可被切换绑定到cpu处理的内核空间的其他线程中处理。
4)协程绑定
为什么要去绑定协程和内核线程,内核线程直接由操作系统调度器执行分配给cpu处理,不去绑定的话还需要切换到用户态手动处理,比较麻烦,效率也比不上操作系统直接管理。
5)gmp模型思维导图
P调用器策略
work stealing
空闲的本地队列优先从其他本地队列中偷取协程,如果偷取不到就从全局队列中获取协程。
hand off
协程阻塞时其他未阻塞的协程绑定到新线程中处理。