gpt4 book ai didi

GO - 代码在函数返回后停止执行

转载 作者:数据小太阳 更新时间:2023-10-29 03:06:10 28 4
gpt4 key购买 nike

所以,我正在尝试构建一个 websocket 服务器。我遇到了这个有趣的错误,我一辈子都弄不明白为什么会这样。

注意:代码片段中的评论仅适用于本文。 阅读它们

我有这个功能:

func Join(ws *websocket.Conn) {
Log.Connection(ws)

enc := json.NewEncoder(ws)
dec := json.NewDecoder(ws)

var dJ g.DiscussionJoin
var disc g.Discussion

Log.Err(dec.Decode(&dJ), "dec.Decode")

ssD := g.FindDiscussionByID(dJ.DiscussionID)

ssDJ := dJ.Convert(ws)

g.DiscHandle <- &ssDJ

disc = ssD.Convert()

Log.Err(enc.Encode(disc), "enc.Encode")

Log.Activity("Discussion", "Joined", disc.DiscussionID.Subject)

fmt.Println("Listening") //This gets called
g.Listen(dec)
fmt.Println("Stoped Listening") //This DOESN'T get called [IT SHOULD]

ssDJ.SSDiscussion.Leave(ssDJ.SSUserID)

Log.Disconnection(ws)
}

造成这种情况的函数是(在我看来)g.Listen(...):

func Listen(dec *json.Decoder) {
timeLastSent := time.Now().Second()
in := Message{}
for ((timeLastSent + ConnTimeout) % 60) != time.Now().Second() {
if err := dec.Decode(&in); err != nil {
continue
} else if in == Ping {
timeLastSent = time.Now().Second()
continue
}
timeLastSent = time.Now().Second()
Messages <- in
in = Message{}
}
fmt.Println("Client timed out!") //This gets called
return
}

我在 Listen

的最后一行尝试了使用和不使用 return

作为对@SimoEndre 的回应,我已将 main 方法排除在代码示例之外,但既然你提到了它,这就是将 g.Messege{} 从 Messeges channel 中取出的函数。
注意: MessageHandler() 在其自己的 go 例程中运行。

func MessageHandler() {
for msg := range Messages {
for _, disc := range LivingDiscussions {
if disc.DiscussionID.UDID == msg.UDID {
go disc.Push(msg)
break
}
}
}
}

最佳答案

查看 Listen 函数,您会注意到它有一个 Messages channel ,该 channel 接收 Message{} 结构,但在main goroutine 它不会被输出。请记住,goroutine 是双向通信 channel ,这意味着如果 channel 确实接收到输入值,则它必须具有输出值, channel 才不会阻塞。

因此您需要创建一个与 Message{} 结构类型相同的 channel

message := make(chan Message{})

然后在 Join 函数中,您必须弹出推送到 channel 的值:

func Join(ws *websocket.Conn) {
...
<-message
}

新输入后更新:

迭代来自 channel 的值是不够的,您需要在 go func() 中执行此操作。

可以使用 select 关键字从不同并发执行的 goroutine 中获取值,这与 switch 控制语句非常相似,有时也称为通信开关。

go func() {   
for msg := range Messages {
for _, disc := range LivingDiscussions {
if disc.DiscussionID.UDID == msg.UDID {
select {
case disc.Push <- msg: // push the channel value to the stack

default :
// default action
}
}
}
}
}()

我不知道您的disc.Push 方法是如何实现的,但是如果您的想法是将接收到的 channel 值推送到堆栈,您必须修改您的代码以发送回数组的 channel 值。在上面的代码片段中,我只是想强调将值推回 channel 很重要。

关于GO - 代码在函数返回后停止执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37114221/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com