go - 隐藏发送到函数调用后面的 channel 是否安全

标签 go concurrency channel goroutine

我有一个名为 Hub 的结构用Run()在自己的 goroutine 中执行的方法。此方法按顺序处理传入的消息。消息从多个生产者(单独的 goroutines)同时到达。当然,我使用 channel来完成这个任务。但现在我想隐藏 Hubinterface 后面能够从其实现中进行选择。所以,使用 channel作为一个简单的 Hub的字段不合适。

package main
import "fmt"
import "time"

type Hub struct {
    msgs chan string
}
func (h *Hub) Run() {
    for {
        msg, hasMore := <- h.msgs
        if !hasMore {
            return
        }
        fmt.Println("hub: msg received", msg)
    }
}
func (h *Hub) SendMsg(msg string) {
    h.msgs <- msg
}

func send(h *Hub, prefix string) {
    for i := 0; i < 5; i++ {
        fmt.Println("main: sending msg")
        h.SendMsg(fmt.Sprintf("%s %d", prefix, i))
    }
}

func main() {
    h := &Hub{make(chan string)}
    go h.Run()
    for i := 0; i < 10; i++ {
        go send(h, fmt.Sprintf("msg sender #%d", i))
    }
    time.Sleep(time.Second)
}

所以我介绍了Hub.SendMsg(msg string)只调用 h.msgs <- msg 的函数我可以将其添加到 HubInterface .作为Go -新手我想知道,从并发的角度来看它是否安全?如果是这样 - 它是 Go 中的常见方法吗? ?

Playground here .

最佳答案

当您将发送移动到方法中时, channel 发送语义不会改变。 Andrew 的回答指出,需要使用 make 创建 channel 才能成功发送,但这始终是正确的,无论发送是否在方法内部。

如果您担心调用者不会意外地结束带有 nil channel 的无效 Hub 实例,一种方法是将结构类型设为私有(private)( hub) 并有一个 NewHub() 函数返回一个完全初始化的 hub 包装在你的接口(interface)类型中。由于该结构是私有(private)的,因此其他包中的代码无法尝试使用不完整的结构文字(或任何结构文字)对其进行初始化。

也就是说,经常可能在 Go 中创建无效或无意义的值,这是可以接受的:net.IP("HELLO THERE BOB") 是有效语法,或者net.IP{}。因此,如果您认为公开您的 Hub 类型更好,那就继续吧。

关于go - 隐藏发送到函数调用后面的 channel 是否安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40566314/

相关文章:

go - 如何解密 privnote 上的消息?

linux - 如何向 SSH 提供密码?

go - 使用 unsafe.Pointer 时 slice 超出范围

c++ - 并发读写的嵌入式数据库

java - 什么情况下 eventloop.inEventLoop() == false ?

go - 这个空的 select-case-default 代码块有什么作用?

go - 缓冲的 golang channel 丢失数据

go - 你如何在 go 中将命令链接到多行?

c++ - 线程间的线程安全通信

java - 使用 ConcurrentMap 双重检查锁定