Go 的并发基础:协程与通道

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情

基础概念

  • 并发:简单说,同一时刻下同时做几件事情。如边听音乐边写掘金文章
  • 进程:就是操作系统中正在执行中的一个程序。比如打开的浏览器
  • 线程:是进程的执行空间,一个进程可以有多个线程。

程序被启动时就会有对应的进程被创建,同时也会启动一个线程,即主线程。主线程结束整个程序就会退出。主线程启动后会启动其他的线程,这些线程就是进程运行时需要的。

  • 协程:Go 中没有线程的概念,只有协程,即 goroutine。

协程,比线程更加轻量,一个程序可以随意启动成千上万个协程。

线程是由操作系统进行调度的,而协程是由 Go runtime 调度的。可以自由控制执行任意个 goroutine,何时执行。

协程

启动协程 goroutine 使用关键字 go

func action(){
    // doing something
}

// 启动 goroutine
go action()

go 关键字后面跟一个方法或者函数的调用,就可以启动一个 goroutine 。需要注意启动协程是并发的过程,其不阻塞主线程的执行。所以以下完整例子,你会得到结果:

func main(){
    go fmt.Println("我是协程1")
    fmt.Println("主协程执行中...")
    // 使用time让主线程等待1秒,主要为了协程执行完后再结束主线程
    time.sleep(time.second)
}

// 执行结果
主协程执行中...
我是协程1

启动了多个协程 goroutine 之后,多个协程之间如何通信呢?

通道 Channel

使用内置的 make 函数声明一个 channel,关键字 chan 表示 channel 类型。

ch := make(chan string)

chan 的操作只有 2 种:

  • 接收:获取 chan 中的值,操作符 <-chan
  • 发送:向 chan 发送值,操作符 chan <-

以上代码,使用关键字 make 创建了一个无缓存 channel ,它的容量是 0,不能存储任何数据。

  • 无缓存 channel,即为同步 channel ,因其容量是0,只能进行传输数据,不存储数据,所以发送和接收是同时进行的,所以称为同步 channel
  • 有缓存 channel ,说明支持存储数据
ch := make(chan string, 5)

有缓存 channel 的内部有一个缓存队列,类似是一个队列,先进先出。当队列为空时则阻塞等待,直到接收到新的元素;当队列满时,也会阻塞等待,直到读取队列或释放。

close(ch)

关闭 channel ,直接调用内置函数close ,关闭后就无法接收数据,再发送数据就会引起 panic 异常。

猜你喜欢

转载自juejin.im/post/7126937110132555807
今日推荐