Golang

1. Goroutine

1.1 进程, 线程和协程和 goroutine

  • 进程,线程: 内核态调度,抢占式 CPU 调度,
  • 协程: 用户态调度, 协作式 CPU 调度,需要协程主动让出 CPU 控制权.

goroutine 本质上就是协程, 不过 golang 对 goroutine 调度进行了封装和处理,当遇到长时间或者进行系统调用时,会主动让出当前 goroutine 的 CPU 控制权,让其他 goroutine 被调度.

总结:

goroutine 线程
栈大小 2KB 8MB
调度 用户态调度 内核态调度
CPU 协作式 抢占式

1.2 实现原理

一般情况网络服务器会有大量的连接需要处理,且总是大量的 I/O + 少量的计算,一个连接建立一个线程会消耗大量系统资源(1. 每个线程栈大小为 8MB, 2.频繁的 I/O 会阻塞当前线程使别的线程被调度,线程切换会带来大量的开销),所以这样不可行.而使用基于事件模式的异步编程模型(select, poll, epoll)可以使用少量的线程来服务大量的网络连接和 I/O 操作,但是需要开发人员手动管理每个连接的上下文,大幅度提高程序的复杂度.

goroutine是在应用层实现的类似于线程的编程模型,程序员可以像编写多线程代码一样编写协程代码,但协程运行时却和异步编程模型相同.
golang 对各种 I/O函数进行了封装,其内部调用了操作系统的异步 I/O 函数,当这些异步函数返回 busy 或者 blocking 时,golang 就将现有的执行序列保存,让程序去拉另外一个goroutine(就绪的)的代码来执行,当 I/O就绪时(基于epoll,select 等)继续在重新调度刚才的goroutine.

1.3 goroutine 调度

  • 协作式调度即非抢占式,程序的切换方式取决于程序本身
  • 抢占式调度: 程序的切换由操作系统(processor)控制

Go1.14 之前 Golang 为协作式的,在一下情况会进行 goroutine 切换

  • 由于系统调用而等待
  • 等待读取或写入未缓冲的通道
  • 由于 time.Sleep() 而等待
  • mutex, select, waitGroup等
    此外Go 会启动一个 sysmon 协程,该函数实现了抢占式调度的功能.sysmon 运行在 M,切不需要 P.
    sysmon 发现 M 已经运行一个 G 10ms 以上时, 他会将该 G 的内部参数 preempt 设置为 true,当该 G 进行函数调用时, G 会检查自己的 preempt 标志,如果为 true, 则它将自己与 M 分离并推入"全局队列". 现在,抢占就成功完成.但是 foo {} 仅是一个死循环,其并不会发生抢占.

1.3.1 异步抢占

在 Go1.14 中引入 非协作式抢占(异步抢占),是一种使用信号的简单有效的算法.
首先, sysmon 仍然会检测到运行了 10 ms 以上的 G.然后 sysmon 向运行 G 的 P 发送信号(SIGURG). Go 的信号处理程序会调用 P 上的 gsignalgoroutine来处理该信号,将其映射到 M 而不是 G,并使其检查该信号. gsignal 看到抢占信号,停止正在运行的 G.使用GODEBUG=asyncpreemptoff=1 可以禁止异步抢占.

全局队列是与“本地队列”不同的队列,本地队列是存储 P 具有的 G。全局队列有以下几个作用。

存储那些超过本地队列容量(256)的 G
存储由于各种原因而等待的 G
存储由抢占标志分离的 G

1.4 GPM

  • G goroutine go 协程
  • P processor 执行器
  • M machine 工作线程

1.4.1 M 工作线程

主线程 M0

运行 runtime.main, 单个实例,

sysmon 线程

创建了新的 m, 这个 m 不需要绑定 p 就可以执行. 与整个调度系统脱离.

  • checkdead, 检查是否所有 goroutine 都已经 锁死, 如果锁死直接调用 runtime.throw,强制退出. 这个操作只在启动的时候做一次
  • 将 netpoll 返回的结果注入到全局 sched 的任务队列
  • 收回因为 syscall 而长时间阻塞的 p, 同时抢占哪些执行时间过长的 g
  • 如果 span 内存闲置超过 5min,那么释放掉

普通线程

就是 GPM 模型里的 M, M 对应的就是操作系统的线程.

M 会从绑定的 p 的本地队列、sched 中的全局队列、netpoll 中获取可运行的 g,实在找不着还会去其它的 p 那里去偷。

2. map

golang 的 map 是 hashmap(c++ stl 是红黑树)

  • 拉链法解决冲突,每个 bucket 可以存储 8 对 key/value
  • 会预先分配一些 bucket 用于溢出
  • 使用高位 hash 与运算来选择桶
  • 使用渐进式 hash 扩容hash 表
  • count/(2B) > 6.5 即翻倍扩容
  • 当 overflow >= 2^B 是触发等量扩容

3. 内存分配

3.1 内存分配核心思想

  • 每次从操作系统申请一大块内存(并不实际分配)
  • 采用 TMalloc 算法, 将内存对象切分为多级,以降低锁粒度
  • 回收对象内存时,并没有将其真正释放掉,只是放回预先分配的大块内存中,以便复用.

3.2 内存结构

spans bitmap arena
512MB 16GB 512GB
存放spans指针,每个 spans 指向page 保存 arena 对应的某个地址是否存在对象,以及对象是否被 gc 扫描过 有 8kb 的 page 组成

3.2.1 arena

arena 即我们通常意义上的heap, 由连续的 page 组成, 多个 page 组成spans,spans 用于具体分配内存,对象分配时会选择大小相近的 span,即一种大小的 span 只给一种确定大小的对象分配,这样来减少内存碎片的产生.

3.2.2 bitmap

bitmap 即位图,一个 byte 标记 4 个对象,分别标记对应地址是否有存在对象和此对象是否被 gc 标记过.

3.2.3

参考资料

https://xargin.com/go-scheduler/
https://blog.csdn.net/lsj1342/article/details/119797966

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容

  • 原文来自博客园作者: q303248153 Golang最大的特色可以说是协程(goroutine)了, 协程让本...
    8411e9740257阅读 1,354评论 0 1
  • G、P、M 三者是golang实现高并发能的最为重要的概念,runtime 通过 调度器 来实现三者的相互调度执行...
    cfanbo阅读 2,631评论 0 4
  • 1. C/C++ 与 Go语言的“价值观”对照 C的价值观摘录 相信程序员:提供指针和指针运算,让C程序员天马行空...
    ywhu阅读 6,899评论 0 13
  • 前言 随着服务器硬件迭代升级,配置也越来越高。为充分利用服务器资源,并发编程也变的越来越重要。在开始之前,需要了解...
    云爬虫技术研究笔记阅读 3,829评论 0 7
  • 一、调度器的由来 调度本身是指操作系统中为每个任务分配其所需资源的方法。 在操作系充中,线程是任务执行的最小单位,...
    thepoy阅读 748评论 0 1