前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言中常见100问题-#67 Being puzzled about a channel size

Go语言中常见100问题-#67 Being puzzled about a channel size

作者头像
数据小冰
发布2022-08-15 15:25:35
2540
发布2022-08-15 15:25:35
举报
文章被收录于专栏:数据小冰
不清楚通道的大小该设置为多少

通道分为缓冲通道和无缓冲通道两种,在使用make内置函数创建通道大小的时候,会出现两个常见的错误:1. 是选择缓冲通道还是无缓冲通道?2. 如果是使用缓冲通道,通道的大小应该设置为多少?本节内容将深入研究这些问题。

首先记住一点,无缓冲通道是没有任何容量的通道。创建无缓冲通道时可以设置通道大小为0,或者不设置大小参数。代码如下:

代码语言:javascript
复制
ch1 := make(chan int)
ch2 := make(chan int, 0)

使用无缓冲通道,无缓冲通道有时也称为同步通道,在接收方从通道中接收数据之前,发送方将会被阻塞。相反,有缓冲通道具有一定容量,在创建的时候必须指定大小,并且大小大于0.

代码语言:javascript
复制
ch3 := make(chan int, 1)

使用缓冲通道,发送者可以在通道没有满的时候,一直往里面发送消息。一旦通道已满,发送操作会被阻塞,直到接收方goroutine收到消息。例如:

代码语言:javascript
复制
ch3 := make(chan int, 1)
ch3 <-1
ch3 <-2

在上面的程序中,第一次向通道ch3中发送数据1不会被阻塞,然而第二次向里面发送数据2时,将会被阻塞,因为此时通道满了。

现在开始讨论两种通道本质区别。通道是实现goroutine之间通信的并发抽象。什么是同步操作呢?在并发程序中,同步意味着我们可以保证多个goroutine在某个时刻处于已知状态。例如,互斥锁提供同步,因为它确保只有一个goroutine可以同时处于临界区。对于通道来说:

  • 无缓冲通道可以实现强同步,的确它可以保证两个goroutine将处于已知状态:一个接收消息,另一个发送消息。
  • 有缓冲通道不提供任何强同步,实际中,生产者goroutine可以发送消息,如果通道未满,则继续可以执行发送消息操作。唯一能保证的是接收goroutine在发送者发送消息之前不会收到消息。这是一种因果关系,就像咖啡,只有先做然后才能喝到。

必须牢记它们之间基本区别,两种通道类型都支持通信。但只有一种提供同步。如果我们需要同步操作,必须使用无缓冲通道。此外无缓冲通道问题可能更容易排查,而缓冲通道会导致模糊的死锁问题,无缓冲通道存在问题会立即表现出来。在某些情况下,使用无缓冲通道更好。例如在通知通道的情况下,通知是通过通道关闭(close(ch))处理的,在这种情况下,使用缓冲通道不会带来任何好处。

回到文章开头提出的第二问题,如果要创建一个缓冲通道,通道的大小设置多少合适呢?有缓冲通道大小可以设置的最小值为1,这个是毫无疑问的。从这个角度来看,有什么更好的理由可以不使用1这个值吗? 下面是应该使用其他值的情况:

  • 在使用类似工作池的模式时,需要设置固定数量的goroutine进行工作任务处理,将处理的数据发送到共享通道上。在这种情况下,可以将共享通道的大小设置为创建的goroutine的数量。
  • 使用通道来解决限制速率问题时,例如,如果我们需要通过限制请求数量提高资源使用率,应该根据限制设置通道大小。

如果实际不是上面这些情况,在设置通道大小的时候则需要谨慎。事实上,经常看到代码库中使用一些神奇的数字来设置通道大小,例如:

代码语言:javascript
复制
ch := make(chan int, 40)

为什么设置通道的大小为40?理由是什么,为什么不设置为50?甚至100?设置这样的值应该要有充分的理由。也许,设置这个值是根据基准测试或性能测试之后决定的,在很多情况下,通过测试对比来设置是一个好的方法。需要注意的是,准确设置通道大小并不是一个容易的事情。涉及到CPU和内存之间的平衡,设置的越小,面对的CPU争用会越大,设置的越大,需要分配的内存会越多。

需要考虑的另一个点来自LMAX Disruptor文章(https://lmax-exchange.github.io/disruptor/files/Disruptor-1.0.pdf)。

❝由于消费者和生产者之间的速度差异,队列通常总是接近满或者接近空,很少能够在生产和消费均衡匹配的平衡中间地带运作。 ❞

所以很难找到一个既不会导致过多争用又不会浪费内存的稳定准确的通道大小。这就是为什么除了上面描述的情况之外,通常最好从默认值1开始设置通道大小。在不确定的情况下,可以通过实际测试来进行衡量评估。

总结,本节内容不能给出通道大小应该设置多少的准确量化,这几乎是不可能的。在不同的实际环境中值可能是不同的,所以很难用一个公式进行计算量化。同步是无缓冲通道带来的保证,有缓冲通道是没有任何同步保证的。如果要设置一个缓冲通道,应该知道其默认大小为1,如果要设置其他值需要谨慎,并且能够评估为什么设置成这个值合理。最后留意一点,使用缓冲通道也可能导致潜在的死锁问题,使用无缓冲通道当出现死锁的时候更容易发现。

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

本文分享自 数据小冰 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 不清楚通道的大小该设置为多少
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档