并发

  1. 当一个函数创建为goroutine时,Go会将其视为一个独立的工作单元,这个单元会被调度到可用的逻辑处理器上执行
  2. Go语言的并发同步模型来自一个叫作通信顺序进程(Communicating Sequential Process,CSP)的泛型,CSP是一种消息传递模型,通过使用通道(channel)在goroutine之间传递数据来传递消息
  3. 如果希望让goroutine并行,必须使用多于一个逻辑处理器,但是要想真正实现并行的效果,程序需要运行在有多个物理处理器的机器上
  4. Sync包中的WaitGroup是一个计数信号量,可以用来记录并维护运行的goroutine,如果WaitGroup的值大于0,Wait方法将会阻塞,使用Done方法则会将其值减一
  5. 基于调度器的内部算法,一个正运行的goroutine在工作结束前,可以被停止并重新调度,这样做的目的是防止某个goroutine长时间占用逻辑处理器,当某个goroutine占用时间时间过长时调度器会停止当前正运行的goroutine,并给其他可运行的goroutine运行的机会
  6. 通过runtime包中的GOMAXPROCS函数可以指定调度器可用的逻辑处理器的数量,而NumCPU函数返回可以使用的物理处理器数量
  7. 同一时刻只能有一个goroutine对共享资源进行读和写操作,否则会产生竞争状态(race condition),可以使用-race工具检测代码里的竞争状态。

锁住共享资源

  1. 原子函数能够以很底层的加锁机制来同步访问整型变量和指针,能够强制同一时刻只有一个goroutine运行并完成对共享资源的操作
  2. 原子函数AddInt64函数可以同步整型值的加法,LoadInt64StoreInt64函数提供了一种安全读和写一个整型值的方式
  3. 另一种同步访问共享资源的方式是使用互斥锁(mutex),互斥锁在代码上创建一个临界区,保证同一时刻只有一个goroutine访问这个临界区代码
  4. Go语言里还可以使用通道,通过发送和接收需要共享的资源,在goroutine之间做同步,创建通道需要使用make函数
  5. 创建通道时不指定第二个参数将会创建无缓冲通道,当指定第二个参数的值时将会创建有缓冲通道,向通道发送以及接收值和指针需要用到<-操作符
  6. 无缓冲通道在接收前没有能力保存任何值,要求发送goroutine和接收goroutine同时准备好才能完成发送和接收操作,如果没有都准备好则会阻塞等待
  7. 有缓冲的通道是一种接收前能存储一个或者多个值的通道,这种通道并不强制要求goroutine之间必须同时完成发送和接收。只有在通道中没有要接收的值时接收动作才会阻塞,只有在通道中没有可用缓冲区容纳被发送的值时,发送动作才会阻塞
  8. 当通道关闭以后,goroutine依旧可用从通道中,但是不能再向通道里发送数据,从一个已经关闭且没有数据的通道中获取数据总会立刻返回并返回一个通道类型的零值,并且还可以通过可选的标志得到通道的状态信息