猜你喜欢
深度探索Go语言

深度探索Go语言

书籍作者:封幼林 ISBN:9787302600855
书籍语言:简体中文 连载状态:全集
电子书格式:pdf,txt,epub,mobi,azw3 下载次数:5555
创建日期:2023-05-01 发布日期:2023-05-01
运行环境:PC/Windows/Linux/Mac/IOS/iPhone/iPad/Kindle/Android/安卓/平板
内容简介

本书主要讲解了Go语言一些关键特性的实现原理,Nicklaus Wirth大师曾经说过:算法+数据结构=程序,语言特性的实现也不外乎就是数据结构+代码逻辑。

全书共分为4个部分:第一部分是基础特性(第1章~第3章),第二部分是对象模型(第4章~第5章),第三部分是调度系统(第6章~第7章),第四部分是内存管理(第8章~第9章)。书中主要内容包括:指针、函数栈帧、调用约定、变量逃逸、Function Value、闭包、defer、panic、方法、Method Value、组合式继承、接口、类型断言、反射、goroutine、抢占式调度、同步、堆和栈的管理,以及GC等。

书中包含大量的探索示例和源码分析,在学会应用的同时还能了解实现原理。书中绝大部分代码都是用Go语言实现,还有少部分使用汇编语言,都可以使用Go官方SDK直接编译。探索过程循序渐进条理清晰,用到的工具也都是SDK自带,方便读者亲自上手实践。

本书适合Go语言的初学者,在学习语言特性的同时了解其实现原理。更适合有一定的Go语言应用基础,想要深入研究底层原理的技术人员。同样适合有一些其他编程语言基础,想要转学Go语言的开发者。


作者简介

封幼林,资深软件工程师,十多年IT从业经验,曾涉足Win32桌面程序开发、Android移动端开发,以及互联网服务器端开发等多个领域。喜欢研究底层技术,用自己的方法探究背后的实现原理。热爱技术交流与分享,创建了微信公众号“幼麟实验室”,致力做一些形象、通透的计算机教程,让开发者“知其然亦知其所以然”。

编辑推荐

本书系统论述Go语言特性,从语言实现的角度深度探索Go语言特性,包含大量的探索示例和源码分析,在学会应用的同时还能了解实现原理。阅读本书不需要精通汇编语言、操作系统,但是需要对进程、线程这类基本概念有所了解。

前言

近几年来,Go语言作为一门服务器端开发语言越来越受欢迎,简洁易学的语法加上天生的高并发支持,还有日益完善的社区,让很多互联网公司开始转向Go语言。随着Go语言生态日趋成熟,各种组件框架如雨后春笋般涌现,市面上相关的书籍也多了起来,但是其中大部分是以应用为主,对于语言特性本身探索一般不太深入。笔者希望能够有一本讲解语言特性及实现原理的书,这也是写作本书的动机。

笔者当年刚参加工作的时候,使用的第一门开发语言是C++。虽然之前在学校用过C语言和汇编语言,但在接触到C++的一些面向对象特性时还是困惑了很久。直到有一天发现了《深度探索C++对象模型》,作者Stanley Lippman当年在贝尔实验室工作,是世界上第1个C++编译器——cfront的实现者,他从一个语言实现者的高度,对一些关键特性的实现原理及其背后的思考进行了详细阐述,使笔者受益匪浅。后来因为工作的原因,笔者开始使用Go语言,因为有了C/C++相关的基础,所以学习起来更加高效。尤其是当年学习C++对象模型,让笔者认识到语言特性也是通过数据结构和代码实现的,所以就按照自己的方式一边学习一边探索。第一次萌生要写点东西的念头是在给从PHP转Go语言的妻子讲完接口动态派发的实现原理后,用她的话来讲就是有种豁然开朗的感觉,并鼓励笔者把这些东西整理一下。后来我们就在微信公众号上以幼麟实验室的名义发布了一系列视频和文章,主要分析语言特性的底层实现。在一年多的时间里,幼麟实验室受到了广大网友的好评与支持,清华大学出版社的赵佳霓编辑也是在此期间联系了笔者,希望笔者能够把自己的探索研究整理成书。因为写作本书的关系,让笔者能够更系统地思考,收获颇多。希望本书能够帮助各位读者,解决大家学习Go语言中遇到的一些困惑。

本书主要内容

第1章介绍x86汇编的一些基础知识,包括通用寄存器、几条常用的指令,以及内存分页的实现原理等。

第2章介绍指针的实现原理,包括指针构成、相关操作,以及Go语言的unsafe包等。

第3章围绕函数进行一系列探索,包括栈帧布局、调用约定、变量逃逸、Function Value、闭包、defer和panic等。

第4章介绍方法的实现原理,包括接收者类型、Method Value和组合式继承等。

第5章围绕接口对Go语言的动态特性展开探索,包括装箱、方法集、动态派发、类型断言、类型系统和反射等。

第6章介绍goroutine的实现,包括GMP模型、goroutine的创建与退出、调度循环、抢占式调度、timer、netpoller和监控线程等。

第7章介绍同步的原理及其相关的组件,包括内存乱序、原子指令、自旋锁、Go语言runtime中的互斥锁和信号量,以及sync.Mutex和channel等。

第8章介绍堆内存管理,包括heapArena、mspan等几种主要的数据结构,mallocgc函数的主要逻辑,以及GC的三色抽象、写屏障等。

第9章介绍栈内存管理,包括goroutine栈的分配、增长、收缩和释放等。

阅读建议

本书写作过程主要使用了Go 1.16及之前的几个版本,为了避免后续版本可能发生的不兼容问题,相关示例建议使用Go 1.13~Go 1.16编译运行。

阅读本书不需要精通汇编语言、操作系统,但是需要对进程、线程这类基本概念有所了解。毕竟Go语言可直接构建生成系统原生的可执行文件,如果想要深入理解一些语言特性的实现原理,还是建议学习并实践一下多线程编程、IO多路复用这类关键技术。

第一部分主要包括指针和函数,笔者希望大家能够通过这部分内容,对运行时栈及函数栈帧的相对寻址方式有深入的理解,为后续探索打下坚实的基础。

第二部分想要表达对Lippman大师的崇高敬意,至今难忘初次阅读《深度探索C++对象模型》时那种“初闻大道,喜不自胜”的心情。按照Lippman大师的解释,对象模型应该是编译器对自定义数据类型的建模,指导了对象内存布局及其他一些数据结构和代码的生成。只有理解了语言特性的实现原理,才真正是磨刀不误砍柴工。

第三部分从服务器端程序开发的角度,梳理了如何从最初的多进程、多线程,逐渐发展到现在的协程。runtime的调度逻辑还是比较复杂的,但是最核心的思想就是IO多路复用与协程的结合,让每个任务有自己独立的栈,而同步的核心就是确立Happens Before条件。

第四部分从堆和栈两方面,梳理了内存管理的实现。内存分配方面应重点关注主要的数据结构。至于GC方面,应先理解宏观层面的整体思想和流程,然后去研究一些细节会更加容易。整个runtime实际上是个不可分割的整体,在这里会看到内存管理对类型系统的依赖。

本书源代码

扫描下方二维码,可获取本书源代码:



本书源代码



致谢

感谢那些喜爱Go语言的网友对笔者的支持; 感谢清华大学出版社的赵佳霓编辑; 感谢我的家人,尤其是和我一起讨论技术问题并帮忙整理书稿的妻子,给予我莫大的支持。

由于时间仓促,并且受限于笔者水平,书中难免有不妥之处,请读者见谅,并提宝贵意见。

封幼林2022年5月













目录

第1章汇编基础


1.1x86通用寄存器


1.1.132位架构


1.1.264位架构


1.2常用汇编指令


1.2.1整数加减指令


1.2.2数据传输指令


1.2.3入栈和出栈指令


1.2.4分支跳转指令


1.2.5过程调用指令


1.3内存分页机制


1.3.1线性地址


1.3.280386两级页表


1.3.3PAE三级页表


1.3.4x64四级页表


1.3.5虚拟内存


1.4汇编代码风格


1.5本章小结


第2章指针(7min)


2.1指针构成


2.1.1地址


2.1.2元素类型


2.2相关操作


2.2.1取地址


2.2.2解引用


2.2.3强制类型转换


2.2.4指针运算


2.3unsafe包


2.3.1标准库与keyword


2.3.2关于uintptr


2.3.3内存对齐


2.4本章小结


第3章函数(44min)


3.1栈帧


3.1.1栈帧布局


3.1.2寻址方式


3.1.3又见内存对齐


3.1.4调用约定


3.1.5Go 1.17的变化


3.2逃逸分析


3.2.1什么是逃逸分析


3.2.2不逃逸分析


3.2.3不逃逸判断


3.3Function Value


3.3.1函数指针


3.3.2Function Value分析


3.3.3闭包


3.4defer


3.4.1最初的链表


3.4.2栈上分配


3.4.3高效的open coded defer


3.5panic


3.5.1gopanic()函数


3.5.2gorecover()函数


3.5.3嵌套的panic


3.5.4支持open coded defer


3.6本章小结


第4章方法(6min)


4.1接收者类型


4.1.1值类型


4.1.2指针类型


4.1.3包装方法


4.2Method Value


4.2.1基于类型


4.2.2基于对象


4.3组合式继承


4.3.1嵌入值


4.3.2嵌入指针


4.3.3多重继承


4.4本章小结


第5章接口(27min)


5.1空接口


5.1.1一个更好的void*


5.1.2类型元数据


5.1.3逃逸与装箱


5.2非空接口


5.2.1动态派发


5.2.2具体实现


5.2.3接收者类型


5.2.4组合式继承


5.3类型断言


5.3.1E To 具体类型


5.3.2E To I


5.3.3I To 具体类型


5.3.4I To I


5.4反射


5.4.1类型系统


5.4.2类型元数据详细讲解


5.4.3对数据的操作


5.4.4对链接器裁剪的影响


5.5本章小结


第6章goroutine(48min)


6.1进程、线程与协程


6.1.1进程


6.1.2线程


6.1.3协程


6.2IO多路复用


6.2.13种网络IO模型


6.2.2示例对比


6.3巧妙结合


6.4GMP模型


6.4.1基本概念


6.4.2从GM到GMP


6.5GMP主要数据结构


6.5.1runtime.g


6.5.2runtime.m


6.5.3runtime.p


6.5.4schedt


6.6调度器初始化


6.6.1调度器初始化过程


6.6.2runtime.schedinit()函数


6.7G的创建与退出


6.7.1相关汇编函数


6.7.2runtime.newproc()函数


6.8调度循环


6.8.1runtime.schedule()函数


6.8.2runtime.findrunnable()函数


6.9抢占式调度


6.9.1Go 1.13的抢占式调度


6.9.2Go 1.14的抢占式调度


6.10timer


6.10.1一个示例


6.10.2数据结构


6.10.3操作函数


6.11netpoller


6.11.1跨平台的netpoller


6.11.2TCP连接的Read()方法


6.12监控线程


6.12.1按需执行timer和netpoll


6.12.2抢占G和P


6.12.3强制执行GC


6.13本章小结


第7章同步(32min)


7.1Happens Before


7.1.1并发


7.1.2并行


7.2内存乱序


7.2.1编译期乱序


7.2.2执行期乱序


7.2.3内存排序指令


7.3常见的锁


7.3.1原子指令


7.3.2自旋锁


7.3.3调度器对象


7.3.4优化的锁


7.4Go语言的同步


7.4.1runtime.mutex


7.4.2semaphore


7.4.3sync.Mutex


7.4.4channel


7.5本章小结


第8章堆(17min)


8.1内存分配


8.1.1sizeclasses


8.1.2heapArena


8.1.3mspan


8.1.4mcentral


8.1.5mcache


8.1.6mallocgc


8.2垃圾回收


8.2.1GC root


8.2.2三色抽象


8.2.3写屏障


8.2.4触发方式


8.2.5GC Worker


8.2.6gctrace


8.3本章小结


第9章栈(8min)


9.1栈分配


9.1.1栈分配初始化


9.1.2栈分配逻辑


9.2栈增长


9.2.1栈增长检测代码


9.2.2栈增长函数


9.3栈收缩


9.4栈释放


9.4.1小于或等于16KB的栈空间


9.4.2大于或等于32KB的栈空间


9.4.3栈释放时机


9.5本章小结



产品特色