为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
慕桂英3389331 2022-06-21 15:49:32
我知道,如果有多个“通信”可以在select声明中进行,则随机选择一个。我正在尝试找到一种替代方法,它可以更喜欢一种“交流”而不是另一种。背景是我正在使用上下文杀死的通道上的 go-routine 中发送值。当我杀死它时,我希望立即关闭通道,但目前代码有时会在关闭之前在通道上发送最终值。这是代码的简化版本:   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。 在操场上尝试一下关于如何重组代码以支持第一种情况有什么想法吗?(即让它总是打印 1200。)
查看完整描述

2 回答

?
波斯汪

TA贡献1811条经验 获得超4个赞

这似乎是不可能的,因为cancel()它不是主 goroutine 中的阻塞操作。正因为如此,当select解除阻塞时,可能会有多种情况可用,并且没有办法让一个渠道优于另一个渠道。任何类型的 check-channel-then-write 方案都将是活泼的,因为在检查后可以取消上下文。

使用done通道并写入它而不是上下文取消将起作用,因为写入done通道将是主 goroutine 的阻塞操作,并且 select 将始终有一个活动案例。


查看完整回答
反对 回复 2022-06-21
?
幕布斯6054654

TA贡献1876条经验 获得超7个赞

请注意,这是一个更新的答案,因为原始答案存在问题。


正如其他人所指出的,如果没有额外的同步,您将无法避免竞争条件。您可以使用 Mutex,但sync.Cond看起来很合适。在下面的代码中,接收 goroutine 表示它已从 chan 接收到值。它在发出信号之前取消上下文(使用Cond.Signal),发送 goroutine 等待信号。这避免了竞争条件,因为上下文状态在被检查之前已更新。


ctx, cancel := context.WithCancel(context.Background())

ch := make(chan int)

cond := sync.NewCond(&sync.Mutex{}) // *** new


go func() {

    defer close(ch)

    cond.L.Lock()                   // *** new

    defer cond.L.Unlock()           // *** new

    for i := 1; ; i++ {

        ch <- i                     // *** moved

        cond.Wait()                 // *** new

        if ctx.Err() != nil {       // *** changed

            return

        }

    }

}()


print(<-ch)

cond.Signal()                      // *** new

print(<-ch)

cond.Signal()                      // *** new

print(<-ch)

cancel()

cond.Signal()                      // *** new

print(<-ch)

cond.Signal()                      // *** new

这是我能看到的最简单的方法,接收 goroutine 在取消上下文后将不会在通道上接收任何值。


查看完整回答
反对 回复 2022-06-21
  • 2 回答
  • 0 关注
  • 102 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号