操作系统的线程创建以及切换是需要开销的,会影响程序的性能。Go致力于尽可能地从内核中获取优势,所以从最开始的时候设计就考虑到了并发性。
M,P,G 编排 为了解决这个问题,Go有他自己的调度者,负责在线程上分配goroutines。这个协调者由3个概念组成,如下:
操作系统的线程创建以及切换是需要开销的,会影响程序的性能。Go致力于尽可能地从内核中获取优势,所以从最开始的时候设计就考虑到了并发性。
M,P,G 编排 为了解决这个问题,Go有他自己的调度者,负责在线程上分配goroutines。这个协调者由3个概念组成,如下:
ℹ️ 这篇文章基于 Go 1.13。
在 Go 中创建的所有 Goroutine 都会被一个内部的调度器所管理。Go 调度器尝试为所有的 Goroutine 分配运行时间,并且在当前的 Goroutine 阻塞或者终止的时候,Go 调度器会通过运行 Goroutine 的方式使所有 CPU 保持忙碌状态。这个调度器实际上是作为一个特殊的 Goroutine 运行的。
前几天在读者交流群里看到一位小伙伴,发出了一个致命提问,那就是:“单机的 goroutine 数量控制在多少比较合适?”。
也许你和群内小伙伴第一反应一样,会答复 “控制多少,我觉得没有定论”。
手动内存管理真的很坑爹(如C C++),好在我们有强大的自动化系统能够管理内存分配和生命周期,从而解放我们的双手。
但是呢,如果你想通过调整JVM垃圾回收器参数或者是优化go代码的内存分配模式话来解决问题的话,这是远远不够的。自动化的内存管理帮我们规避了大部分的错误,但这只是故事的一半。我们必须要合理有效构建我们的软件,这样垃圾回收系统可以有效工作。
关于内存 计算机通过两个机制,去实现内存的高效使用。
第一种机制是虚拟内存。硬盘的容量其实是远远大于内存的(RAM),虚拟内存会在内存不足的时候,把不经常访问的内存的数据写到硬盘里。虽然说硬盘容量比较大,但是它的访问速度却很慢。如果内存和硬盘交换数据过于频繁,处理速度就会下降,计算机就会看上去像卡死了一样,这种现象被叫做抖动(Thrushing)。造成电脑蓝屏的主要原因之一就是抖动。
原文链接机器铃砍菜刀
Go是一门带有垃圾回收的现代语言,它抛弃了传统C/C++的开发者需要手动管理内存的方式,实现了内存的主动申请和释放的管理。Go的垃圾回收,让堆和栈的概念对程序员保持透明,它增加的逃逸分析与GC,使得程序员的双手真正地得到了解放,给了开发者更多的精力去关注软件设计本身。
当我在解决一个问题尤其是新问题的时候,我开始不会去考虑并发(concurrency)是否合适。我首先会去找一系列的解决方式然后确保它有效。然后在可读性和技术方案评估之后,我会开始去考虑并发是否实际合理。有些时候并发的好处是显而易见的,但是有时候并不是很明显。 第一篇文章,我解释了OS调度器的相关内容,我觉得这部分对于你写多线程代码很重要。第二篇里,我讲解了一些Go调度器的一些内容,这部分对于你理解和写go的并发代码很有帮助。在这篇文章里,我会在OS和Go调度器层面让你去深层次的理解并发到底是什么。 这部分内容的目标是:
当你的go程序启动,主机上定义的每一个虚拟内核都会为它分配一个逻辑处理器(P),如果你的处理器上每个物理内核有多个硬件线程(超线程),每个硬件线程对于你的go程序来说就是一个虚拟内核。为了理解这个事情,看一下我的MacBook Pro的系统配置。
图2.1
你可以看到一个单独处理器有4个物理核心。配置表上没说每个物理核心有多少个硬件线程。Intel Core i7 处理器有自己的超线程,也就是每个物理内核上有两个硬件线程。因此Go程序知道并行执行操作系统线程的时候,会有8个虚拟内核可以用
验证一下,看一下下面的程序
L1