代码之家  ›  专栏  ›  技术社区  ›  Sridhar

如何实现对无缓冲通道的非阻塞写入?

  •  13
  • Sridhar  · 技术社区  · 7 年前

    从…起 Effective Go

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

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

    4 回复  |  直到 4 年前
        1
  •  23
  •   Adrian    7 年前

    当它说 os.Notify will not block是要阻止的消息将被丢弃。因此,虽然它确实不会阻塞,但如果不能立即接收到信号,它就不会中继信号。这是通过简单 select :

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

    这就是为什么 Notify 明确指出应使用缓冲通道。还要注意,缓冲通道也可以阻塞,而不仅仅是非缓冲通道;仅当缓冲区已满时,缓冲通道才会阻塞。

    选择 包含在 the tour the spec .

        2
  •  4
  •   Jeremy Huiskamp    7 年前

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

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

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

        3
  •  0
  •   VonC    4 年前

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

    具有 Go 1.17 , the tool vet 这也将更清楚:

    呼叫信号的新警告。在无缓冲通道上通知

    这个 兽医 工具现在警告有关调用 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)
    

    的用户 信号通知 应使用具有足够缓冲空间的通道,以跟上预期的信号速率。

        4
  •  0
  •   lucaswxp    3 年前

    因此,这并不能直接解决问题,因为它需要一个无缓冲的通道,但如果您只想让它在发送时不被阻止,那么这就是我想到的:

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

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

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