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