25 | 运筹帷幄: 协程的运行机制与调度器原理
郑建勋
你好,我是郑建勋。
Go 语言以容易编写高并发的程序而闻名。之前我们介绍 Go 语言的网络模型时,就提到了 Go 运行时借助对 I/O 多路复用的封装还有协程的灵巧调度,实现了高并发的网络处理。不过当时我们还没有深入地审视协程这一最重要的 Go 特性,所以在搭建高并发的爬虫模型之前,让我们先来深入看看协程的运行机制,以及调度器是如何实现灵巧调度的。
线程 VS 协程
协程一般被认为是轻量级的线程。线程是操作系统资源调度的基本单位,但操作系统却感知不到协程的存在,协程的管理依赖 Go 语言运行时自身提供的调度器。因此准确地说,Go 语言中的协程是从属于某一个线程的,只有协程和实际线程绑定,才有执行的机会。
为什么 Go 语言需要在线程的基础上抽象出协程的概念,而不是直接操作线程呢?要回答这个问题,就需要深入理解线程和协程的区别。下面我就简单从调度方式、上下文切换的速度、调度策略、栈的大小这四个方面分析一下线程和协程的不同之处。
调度方式
Go 语言中的协程是从属于某一个线程的,协程与线程的关系为多对多的对应关系。Go 语言调度器可以将多个协程调度到同一个线程中去执行,一个协程也可能切换到多个线程中去执行。
上下文切换的速度
上下文切换的速度
协程上下文切换的速度要快于线程,因为切换协程不必同时切换用户态与操作系统内核态,而且在 Go 语言中切换协程只需要保留极少的状态和寄存器值(SP/BP/PC),而切换线程则会保留额外的寄存器值(例如浮点寄存器)。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
Go语言协程的调度器原理是本文的重点内容。文章首先对比了线程和协程的区别,包括调度方式、上下文切换速度、调度策略和栈的大小。接着深入介绍了Go运行时是如何将协程与线程绑定在一起的,通过逻辑处理器P和特殊的调度协程g0的引入,优化了调度器的性能。调度器的核心策略位于schedule函数中,包括局部运行队列、全局运行队列以及调度算法。文章还介绍了调度时机分为主动调度、被动调度和抢占调度,并以通道的堵塞为例说明了被动调度的过程。此外,还详细解释了协程的上下文切换过程和协程的执行现场保存方式。Go运行时依靠着灵巧的调度实现了对于海量协程的管理,确保了CPU资源的高效利用。文章还介绍了抢占调度的机制,包括执行时间过长的抢占调度和陷入到系统调用中的抢占调度。总的来说,本文通过深入解析Go语言协程的运行机制和调度器原理,为读者提供了深入了解协程技术特点的内容。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Go 进阶 · 分布式爬虫实战》,新⼈⾸单¥68
《Go 进阶 · 分布式爬虫实战》,新⼈⾸单¥68
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(6)
- 最新
- 精选
- Realm1. 谷歌开发者不建议大家获取协程ID,避免开发者滥用协程Id实现Goroutine Local Storage,滥用协程ID会导致GC不能及时回收内存. 2 协程池在大并发的场景中很有必要,虽然goroutine开销很小,无休止开辟Goroutine,会高频率的调度Groutine,在上下文切换上浪费很多资源. https://github.com/panjf2000/ants 这个是一个高性能协程池.2022-12-06归属地:浙江4
- 一打七这节课太干了,全是干货,赞赞赞2022-12-07归属地:北京2
- 牙小木没有goroutineId,Mutex就无法做到可重入。。2023-08-18归属地:北京1
- 啦啦啦还有一类特殊的情况涉及到协程长时间堵塞在系统调用中的问题。这时,当前正在工作的线程会陷入等待状态,等待内核完成系统调用并返回 前面不是说Go用的非堵塞IO+Epoll,为什么M还会被堵住?2023-06-08归属地:新加坡1
- 青鸟飞鱼协程因为在休眠、Channel 通道堵塞、网络 I/O 堵塞、执行垃圾回收而暂停时,被动让渡自己执行权利的过程。这个时候的G是放在局部运行队列吗?还是不是很合适,如果再次调度时,时机没到怎么办呢?2023-02-21归属地:四川
- shuff1e谷歌开发者不建议大家获取协程ID,主要是为了GC更好的工作,滥用协程ID会导致GC不能及时回收内存。如果一个第三方库使用了协程ID,那么使用该库的人将会莫名中招。2022-12-06归属地:上海
收起评论