Go语言圣经 .8.使用共享变量实现并发
使用共享变量实现并发
竞态
竞态是指程序在多个goruntine交叉执行操作时,没有给出正确的结果。
三种避免数据竞态的方法:
- 不要修改变量
- 避免从多个goruntine访问同一变量
- 允许多个goruntine访问同一变量,但同一时间只有一个goruntine可以访问。这种叫作互斥机制。
互斥锁:sync.Mutex
读写互斥锁: sync.RWMutex
内存同步
延迟初始化:sync.Once
竞态检测器(the race detector)
只需要在go build , go run或者go test
命令后面加上-race
的flag,
就会使编译器创建一个你的应用的”修改“版或者一个附带了能够记录所有运行期对共享变量访问工具的test,并且会记录下每一个读或者写共享变量的goruntine的身份信息。
示例:并发非阻塞缓存
goroutine与线程
动态栈
每一个os线程都有一个固定大小的内存块(一般会使2MB)来作栈,这个栈会用来存储当前正在被调用或者挂起的函数的内部变量。
因为这2MB对于小小的goruntine来说是很大的浪费,创建成百上千的goruntine是非常普遍的,如果每一个goruntine都需要这么大的内存的话,会造成很大的浪费。
一个goruntine会以一个很小的栈开始生命周期,一般只需要2kb。但其不是固定的,最大值有1GB
goruntine调度
因为这种调度方式不需要进入内核的上下文,所以重新调度一个goroutine比调度 一个线程代价要低得多。
GOMAXPROCS
Go的调度器使用了一个叫做GOMAXPROCS的变量来决定会有多少个操作系统的线程同时执行Go的代码。
其默认的值是运行机器上的CPU的核心数。
goruntine没有ID号
在大多数支持多线程的操作系统和程序语言中,当前的线程都有一个独特的身份(id)。goroutine没有可以被程序员获取到的身份(id)的概念。