Go语言的并发是是指goroutine运行时是相互独立的,能让某个函数独立于其他函数运行。
并发不是并行。并行是让不同的代码片段同时在不同的物理处理器上执行。并行的关键是同时做很多事情,而并发是指同时管理很多事情,这些事情可能只做了一半就被暂停去做别的事情了。
Go的并发同步模型来自通信顺序进程(Communicating Sequential Processes,CSP)的范型。CSP是一种消息传递模型,通过在goroutine之间传递数据。而不需要对数据进行加锁来实现同步访问。
通道(channel)用于goroutine之间同步和传递数据的数据类型。
goroutinue本质上是协程,但有两点不同:
- goroutinue可实现并行;多个协程可在多个处理器同时跑。而协程同一时刻只能在一个处理器跑。
- goroutinue之间的通信是通过channel(消息队列);而协程的通信是通过yield和resume()操作。
---------------------------------
当一个正在运行的goroutine需要执行一个系统调用,如打开一个文件,线程会和goroutine从逻辑处理器上分离,该线程会继续阻塞,等待系统调用的返回。与此同时,调度器会创建一个新线程,并将其绑定在逻辑处理器上。
之后,调度器会从本地运行队列里选择另一个 goroutine 来运行。一旦被阻塞的系统调用执行完成并返回,对应的 goroutine 会放回到本地运行队列,而之前的线程会保存好,以便之后可以继续使用。
WaitGroup是计数信号量,可以用来维护运行的goroutine。
//wg用来等待程序完成
//计数加2,表示等待两个goroutine
var wg sync.WaitGroup
wg.Add(2)
修改逻辑处理器数量
包 runtime 提供了修改 Go 语言运行时配置参数的能力。
runtime.GOMAXPROCS(runtime.NumCPU())
通道
通过使用管道发送和接收需要共享的资源,在goroutine之间做同步。
声明通道时,需要指定将要被共享的数据的类型。可共享内置类型、命名类型、结构类型、引用类型或指针。
使用make创建管道,
//无缓冲的整形管道
unbuffered := make(chan int)
//无缓冲的字符串通道
buffered := make(chan string, 10)
make的第一个参数需要是关键字chan,之后跟着允许通道交换的数据类型。
向通道发送值或指针需要用到<-操作符。
无缓冲的通道(unbuffered channel):指在接收前没有能力保存任何值。要求发送goroutine和接收goroutine同时准备好,才能进行发送和接收操作。
如果两个foroutine同时没有准备好,通道会导致先执行发送或接收操作的goroutine阻塞。
有缓冲的通道(buffered channel):是一种在被接收前能存储一个或者多个值的通道。
不强制要求 goroutine 之间必须同时完成发送和接收。
只有在通道中没有要接收的值时,接收动作才会阻塞。
无缓冲的通道保证进行发送和接收的 goroutine 会在同一时间进行数据交换;有缓冲的通道没有这种保证。