前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[Golang]Go的channel

[Golang]Go的channel

原创
作者头像
宇宙无敌暴龙战士之心悦大王
修改2023-03-13 18:48:18
4130
修改2023-03-13 18:48:18
举报
文章被收录于专栏:kwai

概论

Go语言官网中,是这么定义Channel这个类型的。

A channel provides a mechanism for [concurrently executing functions] (golang.google.cn/ref/spec#Go…) to communicate by sending and receiving values of a specified element type. The value of an uninitialized channel is nil. 通道为并发执行函数提供了一种机制,通过发送和接收指定元素类型的值来进行通信。 未初始化通道的值为 nil。

“不要通过共享内存的方式进行通信,而是应该通过通信的方式共享内存。” 这句话体现了Go语言对于并发设计的理念,channel 也是实现CSP理论的重要一员。

基本操作

言归正传,下面我们具体聊聊Channel

对于我来说,通道分两种:

  • 无缓冲:无缓冲的在并发编程中,体现在同步。
  • 有缓存:有缓冲则体现在异步。

有无缓冲的通道的创建相差不多,只是参数的差异

Talk is cheap, show me the code —— Linux创始人Linus

下面我们通过一段简单的代码,来描述通道的创建和操作。

代码语言:javascript
复制
     //同步通道
     ch1 := make(chan int)
     //异步通道, 缓冲区大小为1
     ch2 := make(chan int, 1)
 ​
     //写数据
     ch2 <- 1
     //取数据
     <- ch2
     //关闭一个channel
     close(ch2)
复制代码

把上面我们创建通道,其中包括int指定通道中可以放如的类型。

要理解通道,我们可以先把他当作一个FIFO的队列。

我们可以把ch2类比成一个可以放一个元素的队列。

那么ch1呢? 是能放0个元素的通道? 是的,没错!那么怎么通过ch1进行协程间通讯呢?

还记得我们在最上面说过,Channel分两种, 有一种是同步的吗?也就是说,两个协程,要通过 ch1 做通讯,他们必须"握手"。一个协程往ch1中放数据的时候,必须阻塞等待有另外一个携程过来取,发生握手交换数据。

协程对channel的读写流程:

  • 发送方向缓冲区写入数据,会唤醒等待接受的接收方,多个接收方会尝试从缓冲区中读取数据,如果没有读取到会重新陷入休眠;
  • 接收方从缓冲区中读取数据,会唤醒等待写入发送方,发送方会尝试向缓冲区写入数据,如果缓冲区已满会重新陷入休眠;

遇到过的坑

  1. 已经关闭的chan不能写,可以读
  2. 对于channel的遍历最好使用range

源码

Channel的操作比较简单,下面我们通过Go的源码,看看的内部是如何实现的。chan的结构体定义在${GOROOT}/src/runtime/chan.go中。

代码语言:javascript
复制
 ​
 type hchan struct {
     qcount   uint           // total data in the queue
     dataqsiz uint           // size of the circular queue
 ​
     buf      unsafe.Pointer // points to an array of dataqsiz elements
     elemsize uint16
     closed   uint32
     elemtype *_type // element type
     sendx    uint   // send index
     recvx    uint   // receive index
     recvq    waitq  // list of recv waiters
     sendq    waitq  // list of send waiters
 ​
     // lock protects all fields in hchan, as well as several
     // fields in sudogs blocked on this channel.
     //
     // Do not change another G's status while holding this lock
     // (in particular, do not ready a G), as this can deadlock
     // with stack shrinking.
     lock mutex
 }
 ​
复制代码
  • qcount — Channel 中的元素个数;
  • dataqsiz — Channel 中的循环队列的长度;
  • buf — Channel 的缓冲区数据指针;
  • sendx — Channel 的发送操作处理到的位置;
  • recvx — Channel 的接收操作处理到的位置;

通过上面的结构体,我么可以抽象出下面一幅图:

小结

channel 是并发控制中的新成员,虽然他内部也有锁,但是对于我们来说他是无感的,在官方网络库中,Go使用很多通道来做并发控制。

作者:OpenStack 链接:https://juejin.cn/post/7010772020459733005 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概论
  • 基本操作
  • 源码
  • 小结
相关产品与服务
Elasticsearch Service
腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档