Goroutine 浅析

首发于:https://zhuanlan.zhihu.com/p/22297799?refer=lihang

并发还是并行

Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once.[1]

并发的目的在于把当个 CPU 的利用率使用到最高。并行则需要多核 CPU 的支持。

CSP

Communicating Sequential Processes,译为通信顺序进程。是一种形式语言,用来描述并发系统间进行交互的模式。
例如:

COPY = *[c:character; west?c → east!c]
the process repeatedly receives a character from the process named west, and then sends that character to process named east. The parallel composition

[west::DISASSEMBLE || X::COPY || east::ASSEMBLE]
assigns the names west to the DISASSEMBLE process, X to the COPY process, and east to the ASSEMBLE process, and executes these three processes concurrently.[3]

CSP 通过把输入/输出和并发环境下的进程通信作为基础的方法和结构。定义了一套自己的原语,包括:并发执行,输入/输出,循环执行,条件判断等。然后用定义好的语法去实现一些常见的问题,比如:协程,数论,经典的同步问题(生产者消费者,哲学家就餐)。

通过 CSP 的定义,使并发编程能在更高的层次实现,编写的程序不需要关心底层的资源共享、加锁、调度切换等细节,使并发程序的编写更简单。[6]

Go 就是基于 CSP 的思想来实现的并发模型。

Go runtime scheduler

Why need Go scheduler?

主要有两个原因:

  • 线程较多时,开销较大。
  • OS 的调度,程序不可控。而 Go GC 需要停止所有的线程,使内存达到一致状态。[7]

Struct

M 代表系统线程,G 代表 goroutine,P 代表 context。

M:N

There are 3 usual models for threading. One is N:1 where several userspace threads are run on one OS thread. This has the advantage of being very quick to context switch but cannot take advantage of multi-core systems. Another is 1:1 where one thread of execution matches one OS thread. It takes advantage of all of the cores on the machine, but context switching is slow because it has to trap through the OS.[7]

M:N 则综合两种方式(N:1, 1:1)的优势。多个 goroutines 可以在多个 OS threads 上处理。既能快速切换上下文,也能利用多核的优势。

Context switch

在程序中任何对系统 API 的调用,都会被 runtime 层拦截来方便调度。
Goroutine 在 system call 和 channel call 时都可能发生阻塞[8],但这两种阻塞发生后,处理方式又不一样的。

  • 当程序发生 system call,M 会发生阻塞,同时唤起(或创建)一个新的 M 继续执行其他的 G。

If the Go code requires the M to block, for instance by invoking a system call, then another M will be woken up from the global queue of idle M’s. This is done to ensure that goroutines, still capable of running, are not blocked from running by the lack of an available M.[11]

  • 当程序发起一个 channel call,程序可能会阻塞,但不会阻塞 M,G 的状态会设置为 waiting,M 继续执行其他的 G。当 G 的调用完成,会有一个可用的 M 继续执行它。

If a goroutine makes a channel call, it may need to block, but there is no reason that the M running that G should be forced to block as well. In a case such as this, the G’s status is set to waiting and the M that was previously running it continues running other G’s until the channel communication is complete. At that point the G’s status is set back to runnable and will be run as soon as there is an M capable of running it.[11]

P 的作用:

  • 每个 P 都有一个队列,用来存正在执行的 G。避免 Global Sched Lock。
  • 每个 M 运行都需要一个 MCache 结构。M Pool 中通常有较多 M,但执行的只有几个,为每个池子中的每个 M 分配一个 MCache 则会形成不必要的浪费,通过把 cache 从 M 移到 P,每个运行的 M 都有关联的 P,这样只有运行的 M 才有自己的 MCache。[11]

Goroutine vs OS thread

其实 goroutine 用到的就是线程池的技术,当 goroutine 需要执行时,会从 thread pool 中选出一个可用的 M 或者新建一个 M。而 thread pool 中如何选取线程,扩建线程,回收线程,Go Scheduler 进行了封装,对程序透明,只管调用就行,从而简化了 thread pool 的使用。[12]

Goroutine vs Python yield

  • 创建成本:Go 原生支持协程,通过 go func() 就可以创建一个 goroutine。Python 可以通过 gevent.spawn 来新建一个 coroutine,需要第三方库来支持。
  • Goroutine 之间的通信更简单,通过 channel call 即可实现,上下文切换透明(只有少部分需要自己注意 Gosched)。Python 需要 yield 来传递数据和切换上下文(通过一些库封装后对调用者来说也是透明的,比如:gevent/tornado)。
  • Python coroutine 只会使用一个线程,所以只能利用单核。Goroutine 可以被多个线程调度,可以利用多核。

References:

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

推荐阅读更多精彩内容

  • **2014真题Directions:Read the following text. Choose the be...
    又是夜半惊坐起阅读 9,355评论 0 23
  • 十月初一,冬天的第一天,气候渐渐寒冷,人们怕在冥间的祖先缺衣少穿,因此,祭祀衣食用品。在祭祀时,人们把寒衣焚化给祖...
    7默阅读 553评论 1 0
  • 社交圈在哪里,就在你的生活里,把你自己想象为一个圆心,半径100米的地方就是你的社交圈,意中人就将会出现在这些社交...
    而我想成为一个阳光女孩阅读 2,305评论 1 16
  • 春天来的时候,总觉得会发生点什么。 一半在土里安详,一半在风里飞扬, 一半洒落阴凉,一半沐浴阳光。 昨天还是漫山遍...
    璞玉57阅读 218评论 0 1