Do not communicate by sharing memory; instead, share memory by communicating.

不要通过共享内存来通信,而应通过通信来共享内存。

并发与并行

并发指的是在同一时间段内多个线程同时执行,而并行指的是同一时间点上多个线程同时执行。也即并发的程序其实完全可以顺序执行,只有在真正多核心的CPU上程序才能并行执行。并行更关注的是程序的运行层面,并行一般是简单的大量重复,例如GPU中对图像处理都会有大量的并行运算。

Go与并发编程

在并发编程汇中,对共享资源的正确访问需要精确的控制,多数语言采用的加锁的方式来实现线程同步,而Go则采用Channel来在不同的Goroutine中传递共享资源,在任意给定的时刻,最好只有一个Goroutine能够拥有该资源,使得数据竞争从设计层面被杜绝。这也是开篇词所表现的编程哲学的一种具体实现。

互斥锁

考虑以下代码

1
2
3
4
5
6
7
8
9
10
func main() {
var mu sync.Mutex

go func() {
fmt.Println("X")
mu.Lock()
}()

mu.Unlock()
}

互斥锁被加在不同的Goroutine中,而且这两个事件是并发执行的,这也就导致了可能main线程已经要解锁了,而另一个需要加锁的线程还没有加锁,而直接给main线程解锁会导致fatal error: sync: unlock of unlocked mutex

正确的加锁方式如下

1
2
3
4
5
6
7
8
9
10
11
func main() {
var mu sync.Mutex

mu.Lock()
go func() {
fmt.Println("X")
mu.Unlock()
}()

mu.Lock()
}

让main所在的线程执行两次,