【问题标题】:How to implement non-blocking write to an unbuffered channel?如何实现对无缓冲通道的非阻塞写入?
【发布时间】:2018-08-03 19:51:51
【问题描述】:

来自Effective Go

接收器总是阻塞,直到有数据接收。如果通道没有缓冲,发送方会阻塞,直到接收方收到该值。

但是signal.Notify 将信号中继到无缓冲的通道而不会阻塞。这是如何工作的,是否可以与其他 chan

【问题讨论】:

    标签: go channel


    【解决方案1】:

    当它说os.Notify 不会阻塞时,这意味着如果它被阻塞,消息将被丢弃。因此,虽然它确实不会阻塞,但如果不能立即接收到信号,它会中继信号是不正确的。这是通过简单的select 完成的:

    select {
        case channel <- message:
            // message sent
        default:
            // message dropped
    }
    

    这就是为什么Notify 的文档明确指出您应该使用缓冲通道的原因。另请注意,缓冲通道也可以阻塞,而不仅仅是无缓冲通道;缓冲通道仅在缓冲区已满时才会阻塞。

    selectthe tourthe spec 覆盖。

    【讨论】:

    • 嗯,好的。陷入使用 select 从频道读取的常规中 - 没想到。我现在看到了relevant bits
    • 顺便说一下,这种带有默认情况的 select 样式可用于在通道可能多次关闭的情况下安全地关闭通道(因为关闭关闭的通道会导致恐慌)。示例:play.golang.org/p/vDBovMHMKT-。但是,如果可以同时运行通道关闭,则需要使用互斥锁来保护它:play.golang.org/p/f8mg602rOVF
    • @Kaedys 没必要。只需使用sync.Once
    【解决方案2】:

    你总是可以避免阻塞,同时(可能)仍然通过使用另一个 goroutine 来保证交付:

    go func() { channel <- message }()
    

    当然,这只是使用 goroutine 调度器作为频道的替代缓冲区,这可能是明智的,也可能不是明智的。

    【讨论】:

    • 吹毛求疵:如果没有人碰巧从通道读取数据,这个通道和阻塞的 goroutine 会不会在内存中(直到程序结束)?
    • 没错。与缓冲通道相比,一个主要的缺点是如果 goroutine 被阻塞并且没有其他人引用它,它将不会被垃圾收集。我的建议只是一种避免阻塞无缓冲通道的简单方法,同时最大限度地提高仍然传递消息的机会。
    【解决方案3】:

    这就是 Notify 文档明确指出您应该使用缓冲通道的原因

    使用Go 1.17the tool vet 也会更清楚:

    调用信号的新警告。通知无缓冲通道

    vet 工具现在会警告对 signal.Notify 的调用,其中传入信号被发送到无缓冲通道。

    使用无缓冲通道可能会丢失在其上发送的信号,因为signal.Notify 在发送到通道时不会阻塞。

    例如:

    c := make(chan os.Signal)
    // signals are sent on c before the channel is read from.
    // This signal may be dropped as c is unbuffered.
    signal.Notify(c, os.Interrupt)
    

    signal.Notify 的用户应使用具有足够缓冲空间的通道来跟上预期的信号速率。

    【讨论】:

      【解决方案4】:

      所以,这并不能直接解决问题,因为它要求一个无缓冲的通道,但如果你只想让它在发送时不阻塞,这就是我想出的:

      ch := make(chan shared.BlogPost, 1024)
      

      您只是输入了一个比预期大的数字。如果您事先不知道最大容量,那么此解决方案可能不适合您。

      还要记住,go 会急切地分配通道,所以要小心内存使用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-11
        • 1970-01-01
        • 1970-01-01
        • 2016-07-04
        • 2017-06-06
        • 2013-05-16
        相关资源
        最近更新 更多