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

Go中的单向通道有什么意义?

Go中的单向通道有什么意义?

Go
SMILET 2021-05-05 21:38:52
我正在学习Go,到目前为止对它印象深刻。我已经阅读了golang.org上的所有在线文档,并且已经读到了Chrisnall的“ Go编程语言短语”。我了解了渠道的概念,并认为它们将非常有用。但是,在此过程中,我一定错过了一些重要的事情,因为我看不到单向通道的意义。如果我正确地解释了它们,则只能在其上接收只读通道,而只能在其上传输只写通道,那么为什么要有一个可以发送但从不接收的通道?可以将它们从一个“方向”转换为另一方向吗?如果是这样,又没有实际约束又有什么意义呢?它们仅是对渠道目的客户代码的提示吗?
查看完整描述

3 回答

?
眼眸繁星

TA贡献1873条经验 获得超9个赞

可以将通道设置为对接收该通道的任何人都是只读的,而发送方仍具有一个双向通道,他们可以向其写入。例如:


func F() <-chan int {

    // Create a regular, two-way channel.

    c := make(chan int)


    go func() {

        defer close(c)


        // Do stuff

        c <- 123

    }()


    // Returning it, implicitely converts it to read-only,

    // as per the function return value.

    return c

}

呼叫的人F()都会收到一个只能阅读的频道。这对于避免在编译时潜在地滥用通道很有用。因为只读/只写通道是不同的类型,所以编译器可以使用其现有的类型检查机制来确保调用者不会尝试将内容写入没有业务写入的通道。


查看完整回答
反对 回复 2021-05-24
?
浮云间

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

我认为只读频道的主要动机是为了防止腐败和对该频道的恐慌。想象一下您是否可以写入由返回的通道time.After。这可能会弄乱很多代码。

另外,如果您发生恐慌,您可能会:

  • 关闭频道不止一次

  • 写入关闭的频道

这些操作是只读通道的编译时错误,但是当多个go-routine可以写入/关闭通道时,它们可能会导致讨厌的竞争状况。

解决此问题的一种方法是永远不要关闭通道并让它们被垃圾回收。但是,close这不仅用于清理,而且在通道范围超过以下范围时,它实际上也很有用:

func consumeAll(c <-chan bool) {

    for b := range c {

        ...

    }

}

如果该通道从未关闭,则该循环将永远不会结束。如果有多个go-routine正在写入一个通道,那么必须进行很多记账工作,然后再决定哪个程序将关闭该通道。


由于您无法关闭只读通道,因此可以更轻松地编写正确的代码。正如@jimt在他的评论中指出的那样,您不能将只读通道转换为可写通道,因此可以确保只有有权访问通道的可写版本的部分代码才能关闭/写入该通道。


编辑:


至于拥有多个阅读器,这完全可以,只要您考虑就可以了。在生产者/消费者模型中使用时,这尤其有用。例如,假设您有一个仅接受连接并将其写入工作线程队列的TCP服务器:


func produce(l *net.TCPListener, c chan<- net.Conn) {

    for {

        conn, _ := l.Accept()

        c<-conn

    }

}


func consume(c <-chan net.Conn) {

    for conn := range c {

        // do something with conn

    }

}


func main() {

    c := make(chan net.Conn, 10)

    for i := 0; i < 10; i++ {

        go consume(c)

    }


    addr := net.TCPAddr{net.ParseIP("127.0.0.1"), 3000}

    l, _ := net.ListenTCP("tcp", &addr)

    produce(l, c)

}

您的连接处理可能比接受新连接需要更长的时间,因此您希望拥有一个生产者的多个使用者。多个生产者比较困难(因为您需要协调关闭通道的人员),但是您可以在通道发送中添加某种信号量样式的通道。



查看完整回答
反对 回复 2021-05-24
?
潇潇雨雨

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

Go通道基于Hoare的通信顺序过程建模,Hoare的通信顺序过程是并发的过程代数,它以通信参与者(小“ a”)之间的事件流为中心。这样,通道之所以具有方向性,是因为它们具有发送端和接收端,即事件的产生者和事件的使用者。Occam和Limbo也使用了类似的模型。

这很重要-如果通道端可以在不同时间任意用作发送者和接收者,则很难为死锁问题辩解。


查看完整回答
反对 回复 2021-05-24
  • 3 回答
  • 0 关注
  • 281 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信