首先搞懂并发和并行: 多线程程序在单核心的 cpu 上运行,称为并发;多线程程序在多核心的 cpu 上运行,称为并行。 其次搞懂线程和协程:协程类似于用户级线程,是轻量级的;线程比协程使用空间大,一个线程上可以跑多个协程。
Goroutine
Go语言并发编程主要依靠轻量级线程Goroutine实现。调用一个函数时,在函数返回时,会自动销毁该函数创建的goroutine。可以使用go语句在函数调用前创建一个新的goroutine,它的语法形式如下:
go function_name(parameters)
//还可以直接定义一个执行代码块的goroutine
go{
//func...
}
Channel
goroutine实现了并发的运行程序,但各个goroutine之间无法直接共享内存空间,所以使用Channel进行通信。 channel的定义语句使用make,并且在使用时分为接受模式和发送模式两种。
channel_name := make(chan element_type,[buffer_num])
// 发送模式 channel_name <- data_value
// 接收模式 data_value := <-channel_name
锁
为了避免多线程访问相同数据造成竞争,使用锁来进行同步控制。 可以使用sync包下的Mutex/RWMutex/WaitGroup三种方式控制。 但是有以下注意事项:
-
不要在锁持有期间执行长时间的操作,避免阻塞其他的goroutine。
-
避免锁的嵌套,因为嵌套锁可能会导致死锁。
-
要注意同步的粒度,尽可能缩小锁的保护范围,从而减少锁冲突的可能性。
-
在使用RWMutex时,尽量使用读锁,以提高并发性能。
-
在使用WaitGroup等待组时,一定要确保所有的goroutine都调用了Done方法,否则会导致死锁。