这是我参与「第五届青训营 」伴学笔记创作活动的第 2天
1.前言
Go语言的并发通过goroutine实现。goroutine类似于线程,是一种协程,我们可以根据需要创建成千上万个goroutine并发工作。goroutine是由Go语言的运行时(runtime)调度完成,而线程是由操作系统调度完成。
Go语言还提供channel在多个goroutine间进行通信。goroutine和channel是 Go 语言秉承的 CSP(Communicating Sequential Process)通过通讯共享内存的并发模式的重要实现基础。goroutine是非常轻量级的线程。其实goroutine和channel之间的关系,相当于进程与队列之间的关系。
2.goroutine
将一个任务包装进函数,便可轻松使用goroutine执行此函数实现并发,方便快捷。
2.1.启动线程实例
func hello() {
println("hello world")
}
func main() {
go hello()
time.Sleep(time.Second)
}
3.sync.WaitGroup
sleep去等子线程结束有弊端,主进程再退出,存在可能等多了,可能等少了这种情况,因此需要有一种优雅的方式去结束主进程即sync.WaitGroup
func hello(i int) {
println("hello world : " + fmt.Sprint(i))
}
func ManyGo() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(j int) {
defer wg.Done()
hello(j)
}(i)
}
wg.Wait()
}
上例代码中,wg.Add(delta int):计数器加delta,wg.Done():计数器减一,wg.Wait():阻塞直到计数器为0。
4.channel
Go语言的并发模型是CSP(Communicating Sequential Processes),提倡通过通信共享内存而不是通过共享内存而实现通信
goroutine是Go程序并发的执行体,而channel是协程之间的连接,goroutine通过channel通信,类似于进程通信通过队列先进先出的规则,保障了并发的安全性。
channel是一种类型,一种引用类型。声明的通道后需要使用make函数初始化之后才能使用。通道有发送(send):<-、接收(receive):->和关闭(close):close(channel)三种操作。
func CalSquare() {
src := make(chan int)
dest := make(chan int, 3)
go func() {
defer close(src)
for i := 0; i < 10; i++ {
src <- i
}
}()
go func() {
defer close(dest)
for i := range src {
dest <- i * i
}
}()
for i := range dest {
println(i)
}
}
以上src是无缓冲通道,dest为有缓冲通道,二者区别如下:
1.使用无缓冲通道进行通信将导致发送和接收的goroutine同步化。因此,无缓冲通道也被称为同步通道。
2.有缓冲通道的容量表示通道中能存放元素的数量。就像学校的快递柜只有那么个多格子,格子满了就装不下了,就阻塞了,等到别人取走一个快递员才能往里面放一个。
Go语言相较java等语言的并发编程,有goroutine这个轻量级“线程”,使得高并发变得易处理,更高效。