[笔记]A complete journey with Goroutines
原文:A complete journey with Goroutines
什么是Goroutine?
- Goroutine是golang中实现并发(concurrently)执行任务的方式
- Goroutine是在线程基础上轻量级的抽象,相比起线程它们的创建和销毁都很便宜
Goroutine 和线程的区别
- 内存消耗:goroutine最少仅需2kb内存,而线程需要1Mb。goroutine的栈大小可以根据需要扩大或缩小。
- 创建和销毁的代价:创建、销毁线程的代价较大,因为需要从OS获取资源。而goroutine是由go运行时负责创建和销毁的,这些操作相比起来代价很小。
- 切换代价:线程是抢占式(preemptively)调度的,切换过程中需要保存/恢复许多寄存器(16个通用目的的寄存器,程序计数器,栈指针,段寄存器等)。而goroutine是合作式(cooperatively)调度的,并不会和OS内核直接交互,当goroutine切换时,仅仅需要保存/恢复少量寄存器,所以代价比起线程小很多。
我的注:这里有误。coroutine是协作式的,而goroutine是抢占式的,有10ms的时间片限制,这样是为了避免其他goroutine被饿死。
Goroutine 的调度
前面说过,goroutine是合作式调度的。在合作式调度中,没有时间分片的概念。goroutine之间的切换只会在下面这些情况中发生:
- 对channel的阻塞式发送和接收操作
- go 语句 (但是不保证新的goroutine会立即执行)
- 阻塞的系统调用,比如文件和网络IO操作
- 被GC停止
下面介绍goroutine调度的GMP模型。
- G - Goroutine
- M - OS Thread (machine)
- P - Processor
对于一个Go程序,可用线程数量等于 GOMAXPROCS。Go使用M:N的调度器,可以利用机器上的多核:M个goroutine调度在N个OS线程上,而这N个线程又跑在最多 GOMAXPROCS 数量的 processor 上 (N<GOMAXPROCS)。
使用Goroutine的常见错误和避免方式
- 不检查FD限制和内存限制:当创建巨大数量的goroutine时,应该总是检查程序运行的资源限制,包括文件描述符和内存限制
关键词
GOMAXPROCS 用来控制程序中可用于执行goroutine的线程数量。当前Go版本中,默认是逻辑处理器的数量,即runtime.NumCPU()
。
译注:控制线程数量,这句话暂时表示怀疑?我觉得,应该是GMP模型中P的数量。
Comments