代码
调试技术
数据库
- 《Getting started with impala》
- 《mysql 必知必会》
- 《mysql 性能调优与架构实践》
- 《Mysql 技术内幕 InnoDB 存储引擎》
- 《Redis 实战》
- 《Redis 深度历险核心原理和应用实践》
- 《redis设计与实现》
- 《七周七数据库》
- 《深入浅出mysql》
- 《高性能mysql第三版》
- 《MySQL是怎样运行的》
前端
GOLANG
- 《1 The Go Programming Language》
- 《2 The Go Programming Language》
- 《3 The Go Programming Language》
- 《Build Web Application With Golang》
- 《Go101》
- 《Network Programming with go》
- 《Building Microservices With Go》
- 《Building Restful Web Services with Go》
- 《Concurrency In Go》
- 《Go In Action(Go 实战)》
- 《Go学习笔记语言详解》
- 《Go学习笔记源码剖析》
- 《Go语言编程》
JAVA
网络
心理学
PYTHON
创业
UNIX/LINUX
分布式
系统设计
搜索引擎
开发工具
- 《Practical Vim》
- 《Vim8文本处理实战》
- 《Learn vim scrpt the hard way》
- 《Pro Git》
- 《Mastering Vim》
- 《Mastering Vim Quickly》
思维
源码
网站架构微服务
- 《微服务架构设计模式》
- 《从0开始学架构》
- 《web scalavility for startup engineers》
- 《designdatainstensive_application》
- 《designdatainstensive_application2》
- 《clean_architecture》
- 《微服务实战》
- 《微服务设计》
软件工程/项目管理
运维
金融理财
写作
互联网
区块链
技术演讲网课
- 《哔哩哔哩的go微服务实战》
- 《go业务基础库之Error&Context》
- 《Go同步和并发设计模式》
- 《300分钟吃透分布式缓存》
- 《DDD实战课》
- 《分布式技术原理与实战45讲》
- 《架构设计面试精讲》
- 《高并发系统设计40问》
- 《java并发编程78讲》
- 《中间件核心技术与实战讲》
职场
《Go学习笔记源码剖析》
13 准备
基于Go 1.5.1,测试环境为Linux AMD64,且不包含32位内容。
14 引导
事实上,编译好的可执行文件真正的执行入口并非我们所写的main.main函数,因为编译器总是会插入一段引导代码,完成诸如命令行参数、运行时初始化等工作,然后才会进入用户逻辑。
用使 gdb 调试器进入入口
15 初始化
- 所有init函数都在同一个goroutine内执行。
- 所有init函数结束后才会执行main.main函数。
16 内存分配
Go编译器支持逃逸分析(escape analysis),它会在编译期通过构建调用图来分析局部变量是否会被外部引用,从而决定是否可直接分配在栈上。 编译参数-gcflags"-m"可输出编译优化信息,其中包括内联和逃逸分析。
17 垃圾回收
大事记:
- 2014/06,Go 1.3:并发清理。
- 2015/08,Go 1.5:三色并发标记。
注意:此处所说并发,是指垃圾回收和用户逻辑并发执行。
按官方说法,Go GC的基本特征是“非分代、非紧缩、写屏障、并发标记清理”。
与之前版本在STW(Stop the world)状态下完成标记不同,并发标记和用户代码同时执行让一切都处于不稳定状态。用户代码随时可能修改已经被扫描过的区域,在标记过程中还会不断分配新对象,这让垃圾回收变得很麻烦。
究竟什么时候启动垃圾回收?过早会严重浪费CPU资源,影响用户代码执行性能。而太晚,会导致堆内存恶性膨胀。如何正确平衡这些问题就是个巨大的挑战。
所有问题的核心:抑制堆增长,充分利用CPU资源。为此,Go引入一系列举措。
三色标记和写屏障、控制器、辅助回收
18 并发调度
+--------------------sysmon---------------//------+
| |
| |
+---+ +---+-------+ +--------+ +---+---+
go func() ---> |G| ---> |P|local| <===balance===> |global| <--//--- |P|M|
+---+ +---+-------+ +--------+ +---+---+
| | |
| +---+ | |
+----> |M| <---findrunnable---+---steal<--//--+
+---+
| 1. 语句go func() 创建G
| 2. 放入P本地队列(或平衡到全局队列)
+---execute<-----schedule 3. 唤醒或新建M执行任务
| | 4. 进入调度循环schedule
| | 5. 竭力获取待执行G任务并执行
+-->G.fn-->goexit--+ 6. 清理现场,重新进入调度循环
本节介绍与任务执行有关的几种暂停操作:
Gosched: 可被用户调用的runtime.Gosched将当前G任务暂停,重新放回全局队列,让出当前M去执行其他任务。我们无须对G做唤醒操作,因为它总归会被某个M重新拿到,并从“断点”恢复。
gopark:与Gosched最大的区别在于,gopark并没将G放回待运行队列。也就是说,必须主动恢复,否则该任务会遗失。
notesleep:相比gosched、gopark,反应更敏捷的notesleep既不让出M,也就不会让G重回任务队列。它直接让线程休眠直到被唤醒,更适合stopm、gcMark这类近似自旋的场景。
Goexit:用户可调用runtime.Goexit立即终止G任务,不管当前处于调用堆栈的哪个层次。在终止前,它确保所有G.defer被执行。
stopTheWorld:用户逻辑必须暂停在一个安全点上,否则会引发很多意外问题。因此,stopTheWorld同样是通过“通知”机制,让G主动停止。比如,设置“gcwaiting=1”让调度函数schedule主动休眠M;向所有正在运行的G任务发出抢占调度,使其暂停。
考参:G-P-M 模型。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论