1、并发和并行
并发和并行是go语言中非常重要的两个概念,在我理解来看
首先,并行这两个字我们从字面意义上就可以理解到是两条直线同时向一个方向延伸,那么并发肯定是与并行有区别的两种状态,并发是对同一资源的交替使用
2、Go中的线程
Go语言中并不直接使用线程的概念,而是引入了goroutine(类似轻量级线程)的概念来实现并发。
创建和启动goroutine非常简单,只需要在函数调用前加上go关键字即可。
例如:
go myfunc() // 启动一个新的 goroutine 并执行 myfunc 函数。
这时候,myfunc()会并发地运行在一个独立的 Goroutine,而且 go myfunc()会立即返回,不会等待 myfunc()完成,程序会跳过 go myfunc() 继续执行后面的代码。
3、Go中的通信
在 Go 语言中,channel 是一种特殊的类型。无缓存的 channel 是在接收前没有保存值的能力,只有在直接进行发送和接收的操作时才允许数据项通过。有缓存的 channel 有一定的容量,为此在该类型的 channel 中,前 n 个元素可无阻塞的写入。当向 channel 中写入数据时,可以不需要同时读取数据。
创建 Channel 的方式为:
ch := make(chan int) // 创建一个无缓冲的 channel
ch := make(chan int, n) // 创建一个有缓冲的 channel,n 是 buffer 的大小
在使用 Channel 时,有两个重要的操作,即发送与接收。其操作如下:
发送操作:
ch <- v // 将v发送至 channel ch.
接收操作:
v := <-ch // 从ch接收并且赋值给 v。
4、Go中的锁
Go语言中的锁主要用于处理并发编程中的数据一致性问题,即确保同一时间只有一个goroutine能访问共享数据。在Go语言中,通过sync包提供了两种锁类型:互斥锁(sync.Mutex)和读写锁(sync.RWMutex)。
互斥锁是最简单的一种锁,对共享资源的访问进行严格的排他控制。如果一个goroutine持有了互斥锁,那么其他goroutine就无法再获取到该互斥锁,只能等到已获取锁的goroutine释放后才能其它goroutine获取到锁。
读写锁分为两部分,读锁和写锁。与互斥锁相比,读写锁更适合读多写少的场景。当一个goroutine持有读锁时,其他goroutine可以继续获得读锁,但无法获取写锁; 当一个goroutine持有写锁时,其他goroutine则不论读还是写都无法获取锁。
互斥锁和读写锁的使用方法很类似,通过Lock()方法加锁,Unlock()方法解锁。读写锁额外提供了RLock()方法加读锁,RUnlock()方法解读锁。在使用锁时要特别注意避免死锁情况的产生。