能力有限顶多比机翻强些,或许还不如。在翻译的过程中精读,无法做到信雅达,但求别混淆大家视听。之前开过Mysql的坑,一直没填上,想来也应该不会去填了。
Golang从语法上来说并不难,一些开源的组件用着还行不错,相对Java而言成熟度欠佳。
之前学习Java内存回收学得比较懵懂,看了一大堆内容没能抓住重点。导致常常看了没过两个月又忘了又去看。
这次打算精读,读完之后带着问题来整理。
本篇是三篇系列文章的开篇,将会深入浅出的阐述Go语言调度器的机制与语义。将会着重于操作系统调度。
系列文章导引:
1)深入浅出Go语言调度器:第一部分 - 系统调度器
2)深入浅出Go语言调度器:第二部分 - Go 调度器
3)深入浅出Go语言调度器:第三部分 - 并发
Go 调度器的设计与实现,使得它在多线程领域表现得更高效、运行得更稳定。这主要在于Go 调度器为代码提供了相较操作系统调度器更好的硬件协作方式。不过代码的设计与实现是否完美的与硬件协作,以及Go 调度器如何工作,并不是本篇讨论的重点。文章将会着重探讨系统调度器和Go 调度器,从而为你的多线程软件设计提供帮助。
这一系列文章将会聚焦于调度器的高级机制和语义。我会阐述足够的细节,从而让你更形象的了解它是如何工作的,使得你在代码设计时做出更好的决策。尽管在并发编程中有很多知识需要了解,但调度器机制和语义仍然是比较基础的部分。
操作系统调度器是一个复杂的程序。它们必须考虑运行时硬件结构和设置,这包括但不限于多处理器核心、CPU 缓存和非统一内存访问架构(NUMA)。脱离这些知识,系统调度器无法达到如此高效。值得庆幸的是宏观的熟悉操作系统工作模型就可以了,无需深入研究这一些话题。
你的程序就是一系列机器指令,按照顺序一个接一个的执行。为了实现这一点,操作系统采用了线程(Thread)的概念。线程的职责是执行分配给它的指令,一直执行到没有更多指令需要执行为止。这就是为什么,我把线程称作“执行路径”。
你的每个程序都会创建一个进程,每个进程都会初始化线程,而后线程又可以创建更多线程。所有线程相互独立地运行,并且调度器在这一层面工作,而不是进程级别。线程能够并发(轮流使用一个单独内核),或是并行(同时使用多个不同的内核)。线程同时维护他们自身的状态,以确保安全、隔离、独立的执行它们的指令。
系统调度器的责任是一旦有线程可以执行,确保内核不闲着。它必须构建一个所有线程同时都在运行的错觉。在此过程中,调度器需要根据线程优先级策略先后排序,高优先级在前,低优先级在后。当然低优先级的也不会完全被饿死。调度器同时需要快速且机智做出决策,以最小化调度延迟。
实现以上描述的调度算法很多,不过幸运的是,业内已积累了数十年的经验。为了更好的理解这些,接下来我们看几个重要的概念。
程序计数器(program counter 简称PC),有时也被称作指令指针(instruction pointer 简称IP),被用做跟踪线程下一个要执行的指令。在多数处理器中,程序计数器指向下一个指令,而不是当前指令。
https://www.slideshare.net/JohnCutajar/assembly-language-8086-intermediate
如果你曾经看过Go程序的堆栈跟踪(stack trace),你可能注意到每行末尾哟一个十六进制数字。注意观察Listing 1中的+0x39
和+0x72
。
goroutine 1 [running]:
main.example(0xc000042748, 0x2, 0x4, 0x106abae, 0x5, 0xa)
stack_trace/example1/example1.go:13 +0x39 <- LOOK HERE
main.main()
stack_trace/example1/example1.go:8 +0x72 <- LOOK HERE
这些数字代表着程序计数器中记录的数值与相应函数顶部的偏移量。
原文:https://www.cnblogs.com/snifferhu/p/11670180.html