go - 在选择中支持一种通信(chan)

标签 go select channel

我知道如果有多个“通信”可以在 select 中进行。声明一个是随机选择的。我正在尝试找到一种替代方法,它可以更喜欢一种“交流”而不是另一种。
背景是我正在使用上下文杀死的 channel 上的 go-routine 中发送值。当我杀死它时,我希望立即关闭 channel ,但目前代码有时会在关闭之前在 channel 上发送最终值。
这是代码的简化版本:

   ctx, cancel := context.WithCancel(context.Background())
   ch := make(chan int)

   go func() {
      defer close(ch)
      for i := 1; ; i++ {
         select {
         case <-ctx.Done():
            return
         case ch <- i:
         }
      }
   }()

   print(<-ch)
   print(<-ch)
   cancel()
   print(<-ch)
   print(<-ch)
这有时会打印 1200,但通常会打印 1230。Try it on the playground
关于如何重组代码以支持第一种情况有什么想法吗? (即让它总是打印 1200。)

最佳答案

这似乎是不可能的,因为 cancel()不是主 goroutine 中的阻塞操作。正因为如此,当select unblocks 可能有多种情况可用,并且没有办法偏爱一个 channel 而不是另一个 channel 。任何类型的 check-channel-then-write 方案都将是活泼的,因为在检查后可以取消上下文。
使用 done channel 并写入它而不是上下文取消将起作用,因为写入 done channel 将是主 goroutine 的阻塞操作,并且 select 将始终有一个事件案例。

关于go - 在选择中支持一种通信(chan),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63200374/

相关文章:

MYSQL在一个join中获取其他表的数据

clojure - 创建需要多次关闭的 channel

c# - WCF channel 和 ChannelFactory 缓存

php - 如何使用 MySql 和 PHP 存储/处理多个表的数据

MySql 嵌套 View 返回空白或 0 而不是空值

rest - 预检未通过控制检查访问控制允许来源不存在

go - 如何停止协程

synchronization - 在 channel 上阻塞发送一个错误的同步范例以及为什么

go - 在响应中包含 err.Error() 总是安全的吗?

go - 在同一命名空间中连线生成具有相同名称的第二个函数