Go 语言进阶 - 工程进阶 | 青训营笔记

60 阅读3分钟

这是我参与「第五届青训营 」笔记创作活动的第2天

并发编程

Goroutine

goroutine是Go语言中开启协程的一种方式,在Go语言中,我们通过goroutine实现并发以及并行任务,goroutine与我们常说的协程有以下区别:

  1. 协程是用户态的,它的管理依赖于Go语言运行时的调度器。Go语言中的协程与线程的对应关系为M:N,即多对多关系 -> 一个线程可以运行多个协程,一个协程可以在多个线程中执行
  2. 协程的切换无须经过操作系统用户态与内核态切换以及协程切换只需要保留少量的寄存器变量值,这样就导致协程的上下文切换速度更快
  3. 线程的调度方式大部分时间是抢占式,而协程是协作式调度,当一个协程处理完自己的任务后,可以主动将执行权限让渡给其他协程。
  4. 线程的栈的大小为MB级别,而协程的栈的大小为KB级别,这样我们就能创建很多的协程来运行一些并发和并行任务。

开启协程

for i := 0; i < 10; i++ {
   go func(j int) {
      fmt.Println(j)
   }(i)
}
time.Sleep(1000)

以上是开启了多个协程并发打印数字,我们可以看见开启协程很简单,就是一个go关键字,然后我们这里需要time.sleep(1000),这个到后面再讲(见sync)

channel

声明

    src := make(chan int) // 无缓冲
    dest := make(chan int, 3) // 大小为3

无缓冲的通道只有在有人接收值的时候才能发送值,就像你住的小区没有快递柜和代收点,快递员给你打电话必须要把这个物品送到你的手中(参考地鼠文档)。有缓冲的通道我理解为信箱,可以放多个信件,当超过信箱大小时也不行,不超过的话就无所谓了。

应用

在Go语言中,我们通过通信来共享内存而不是通过共享内存来通信(这个在Go语言中也有,就在下节),所以channel我们是用来多个协程进行通信的东西,并且channel的底层其实是一个循环队列,所以也有先进先出的特点,这样能确保我们发送的信息有序

其他

无缓冲的通道通常用来阻塞一个协程,例如我们可以在main里接收一个管道,这样也能达到time.sleep的效果。有缓冲的通道用途更多,在此就不赘述了。

sync

相信大家对sync这个单词缩写,这是golang中用来同步的包,其中有lock以及WaitGroup等,相信大家对lock不陌生,他就是我们通常说的全局锁,WaitGroup其实也就像c里面的pthread_join,但是是等待加入等待队列的协程。根据上文埋的坑,我们可以将协程都Add到WaitGroup中,再用defer延迟调用Done,这样就能在主协程中实现阻塞,也就能代替time.sleep了。