2008年,Russ Cox提交的初版Mutex的代码如下:
// CAS操作,当时还没有抽象出atomic包
func cas(val *int32, old, new int32) bool
func semacquire(*int32)
func semrelease(*int32)
// 互斥锁的结构,包含两个字段
type Mute
数据竞争是并发程序中最常见的,也是最难发现的并发问题,所幸的是,Go内置了在一定程度上可以发现竞争问题。你可以在测试数据竞争检测器(data race detector),或者运行程序时使用-race开启数据竞争检测器,或者在编译程序时开启,编译好的二进制程序在运行时也可以开启数据竞争检测:
go test -race mypkg // 测试mypkg包
go run -race mysr
因为并发编程中有竞争条件和数据竞争的问题,我们才需要将代码片段设定为临界区,通过使用Mutex等同步原语将临界区保护起来。接下来,我们来熟悉Go标准库的Mutex 的使用方法,看看它是如何保护临界区,解决竞争条件和数据竞争的问题的。
一个并发问题有时候,我们很清楚地知道临界区或者共享资源,能主动地发现数据竞争问题;但是有时候,数据竞争问题却不那么容易被发现,比如下面这段代码,你认为有数据竞争
了解Go运行时对goroutine的调度,对于深入分析和理解并发程序还是很有帮助的。
当操作系统的线程切换到另一个线程时,CPU会执行一个操作,叫作上下文切换(context switch),操作系统会在中断、系统调用时执行线程上下文切换。线程上下文切换是一种昂贵的操作,因为操作系统需要将用户态转移到内核态,保存要切换线程的执行状态,也就是将一些重要寄存器的值和进程状态保存在线程控制块数据结构中。当恢复线程的运行时,需要将这些状态加载到集群中,从内核态转移到用户态。想想就比较复杂、耗时,如果又涉及进程上下文切换,就更加耗时了。goroutine的调度是由Go运行时控制的,每个编译的Go程序都
一般来说,正如我们平常理解的那样,将串行程序修改为并行程序之后,其性能会得到提升。但也不是绝对的,在某些情况下,串行编程性能反而更好。
下面这个例子是快速排序的串行实现。
// 快速排序中的分区,把a分成左右两部分,左边部分小于右边部分
func partition(a []int, lo, hi int) int {
pivot := a[hi] // 将最后一个值作为分界值
i := l
当今很多高级编程语言都支持并发编程,但是Go语言绝对是很特殊的那一个,一开始它就从语言设计上为并发编程提供了最简单的方式,并且设计了对线程更轻量级的goroutine,还为CSP模型提供了容易使用的channel类型,并将其作为内建类型直接提供。
2019年,在Go Time对Rob Pike和Robert Griesemer的访谈节目中,Rob Pike 谈到发明Go语言的想法时说道,“我们听到了一个C++新版本发
