前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >go语言学习(五):通道的用法

go语言学习(五):通道的用法

作者头像
jinjunzhu
发布2020-08-20 10:02:59
3740
发布2020-08-20 10:02:59
举报
文章被收录于专栏:个人开发个人开发

go语言的作者Rob Pike认为,不要通过共享内存来实现通信,而应该通过通信来共享内存。多个goroutine之间可以通过通道来传递数据。通道是并发安全的,类似于一个FIFO的队列。go语言的通道定义需要使用make语句,如下,定义了一个存放3个int类型元素通道并向通道中输入了3个元素。同时用for循环取出。

代码语言:javascript
复制
func main() {  ch1 := make(chan int, 3)  ch1 <- 2  ch1 <- 1  ch1 <- 3  close(ch1)  for elem1 := range ch1 {    fmt.Printf("The first element received from channel ch1: %v\n", elem1)  }}

上面的代码会在循环中不断从通道中取出元素,即使通道已经关闭了也会取出剩下的元素。如果通道没有关闭并且取完了通道中的元素,循环就会阻塞。

注意:

1)通道发送完数据后应该关闭。

2)发送操作和接受操作都会阻塞通道。

3)如果不指定通道的容量,那通道容量默认是0,称作非缓存通道;如果指定通道ro容量,如上面示例,称作缓存通道。

4)如果缓存通道容量满了,发送操作就会阻塞,直到接收通道接收了元素;如果通道空了,接收操作就会阻塞,直到有元素写入通道。如果是非缓存通道,则发送操作和接收操作都在执行时才不会被阻塞。这就说明缓存通道是一个异步操作,而非缓存通道是一个同步操作。

5)以下几种情况会跑出panic。

a.关闭一个已经关闭的通道

b.向关闭的通道发送或接收数据

c.通道没有初始化,而是一个nil

我们把接收操作赋值给2个参数,第二个参数就能判断通道是否已经关闭。比如用for循环接收通道中的元素,代码如下:

代码语言:javascript
复制
for {    elem, ok := <-ch1    if !ok {      fmt.Printf("Receiver: close channel\n")      break    }    fmt.Printf("Receiver: received an element:%v\n", elem)  }

在我们开发过程中,有时候为了在方法参数中定义一个通道来收发数据,会定义一个单向通道,如下面代码,第一个通道只能发,第二个通道只能收

代码语言:javascript
复制
var sendChan = make(chan<- int, 1)var receiveChan1 = make(<- chan int, 1)
代码语言:javascript
复制

还可以定义返回值是单向通道的函数,如下:

代码语言:javascript
复制
func getIntChan() <- chan int{}func getIntChan1()  chan <- int{}
代码语言:javascript
复制

go语言为通道提供了select语句配合使用,类似于java中的switch,也有一个默认的分支,示例如下:

代码语言:javascript
复制
func main() {  // 准备好几个通道。  intChannels := [3]chan int{    make(chan int, 1),    make(chan int, 1),    make(chan int, 1),  }  // 随机选择一个通道,并向它发送元素值。  index := rand.Intn(3)  fmt.Printf("The index: %d\n", index)  intChannels[index] <- index  // 哪一个通道中有可取的元素值,哪个对应的分支就会被执行。  select {  case <-intChannels[0]:    fmt.Println("The first candidate case is selected.")  case <-intChannels[1]:    fmt.Println("The second candidate case is selected.")  case elem := <-intChannels[2]:    fmt.Printf("The third candidate case is selected, the element is %d.\n", elem)  default:    fmt.Println("No candidate case is selected!")  }}
代码语言:javascript
复制

注意:在for循环中使用select,如果要屏蔽某个case分支,可以将通道赋值为nil

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 jinjunzhu 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档