Go goroutine和channel详解

掘金城管希 · · 559 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

不要通过共享内存来通信,要通过通信来共享内存。

Go 支持两种方式的并发模型: communicating sequential processes(CSP) 和 shared memory multithreading,前者是 goroutine 和 channel 并发模型实现的基础,后者是传统的共享内存的方式,也就是多线程模型。

如何理解 CSP ?简单来说就是通过在不同的 goroutine 之间传递 value 来维护并发的下不同 goroutine 的状态,但是对变量的使用、修改要限制在单一的 goroutine 中。

定义

在 Go 中可以并发执行的活动单元称之为 goroutine。当一个 Go 程序启动时,一个执行 main function 的 goroutine 会被创建,称之为 main goroutine。创建新的 goroutine 可以使用 go 语句,像这样: go f(),其中 f 是一个函数。使用 go 语句开启一个新的 goroutine 之后,go 语句之后的函数调用将在新的 goroutine 中执行,而不会阻塞当前的程序执行。

如果说 goroutine 是并发执行的一个 Go program, channel 就是它们之间的连接通道,它提供了 goroutine 之间相互通信的机制。channel 是有类型的,channel 中使用的 type 称之为 element type,比如 int 类型的 channel 写作为 chan int

Go 使用 make 内建函数创建 channel。

ch := make(chan int)
复制代码

同 map 一样,一个 channel 引用着 make 创建的底层数据结构上,当把 channel 当做函数参数传递时,实际上是拷贝一份 reference,也就是说函数内部和外部引用的是相同的数据结构,所以在函数内部可以直接修改 channel 的值。同其它 reference type 一样,channel 的 zero value 是 nil

channel 是可比较的

channel 是可比较的,如果两个 channel 的类型相同,它们可以彼此相互比较

ch01 := make(chan int)
ch02 := make(chan int)
if ch01 == ch02 {
    fmt.Println("ch01 == ch02")
} else {
    fmt.Println("ch01 != ch02") // return
}
复制代码

两个不是 nil 的 channel 比较实际上比较的他们的 reference 是否相同,如果他们都引用同一个 channel,则他们相同:

func main() {
    ch01 := make(chan int)
    func02(ch01, ch01)
}

func func02(a chan int, b chan int) {
    if a == b {
        fmt.Println("a == b") // return
    }
}
复制代码

当然 channel 也可以和 nil 比较,没有初始化的 channel 就是 nil:

var ch02 chan int
if ch02 == nil {
    fmt.Println("ch02 is nil") // return
}
复制代码

channel 的基本操作

channel 有三种基本的操作 send、receive、close。

send

channel 支持 send 操作,意思是向 channel 中发送数据,Go 使用 <- 操作符来实现 send:

ch <- x //send
复制代码

被send的对象是在 <- 在 channel 右侧。

receive

channel 还支持 receive 操作,意思是从 channel 中取出数据,Go 也是使用 <- 操作符来实现 receive:

x, ok := <- ch //receive
复制代码

receive 时 <- 在左侧,如果一个执行 receive 时没有用任何变量来赋值,则该值被抛弃,receive操作可以获得2个参数,ok可以用来判断channel是否关闭,从一个已关闭的channel获取值会得到零值,陷入死循环

receive 的这个操作常常被用来做状态同步:

<- ch
复制代码

close

channel 还支持第三种操作 close,如果 channel 被 close,表明 channel 不会再 send 任何值了,如果还继续对 channel 执行 receive 操作,当 channel 中的值消耗完毕之后,之后返回的是对应 element type 的 zero value,如果对 channel 执行 send 操作,将会引起 panic:

close(ch)
ch <- x  // panic
复制代码

close 操作常常和 for 语句配合使用,表示一个 channel 不再产生新的值:

for x := range ch {
   fmt.Print(x) 
}
复制代码

close channel 之后,for 循环将结束。

原文


有疑问加站长微信联系(非本文作者)

本文来自:掘金

感谢作者:掘金城管希

查看原文:Go goroutine和channel详解

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

559 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传