去 GC 停止我的 goroutine?

Go GC stopping my goroutine?

我一直在尝试从 Java 和 C 等更传统的语言进入 Go,到目前为止,我一直在享受 Go 提供的深思熟虑的设计选择。但是,当我开始我的第一个 "real" 项目时,我 运行 遇到了一个几乎没有人遇到过的问题。

我的项目是一个发送和接收数据包的简单网络实现。大体结构是这样的(当然简化了):

客户端通过服务器管理net.Conn。这 Client 创建一个 PacketReader 和一个 PacketWriter。这两个 运行 在不同的 goroutine 中无限循环。 PacketReader 接受一个由客户端实现的带有单个 OnPacketReceived 函数的接口。

PacketReader 代码如下所示:

go func() {
    for {
        bytes, err := reader.ReadBytes(10) // Blocks the current routine until bytes are available.
        if err != nil {
            panic(err) // Handle error
        }
        reader.handler.OnPacketReceived(reader.parseBytes(bytes))
    }
}()

PacketWriter 代码如下所示:

go func() {

    for {
        if len(reader.packetQueue) > 0 {
            // Write packet
        }
    }
}()

为了使 Client 阻塞,客户端创建了一个由 OnPacketReceived 填充的通道,如下所示:

type Client struct {
    callbacks map[int]chan interface{}
    // More fields
}

func (c *Client) OnPacketReceived(packet *Packet) {
    c.callbacks[packet.Id] <- packet.Data
}

func (c *Client) SendDataBlocking(id int, data interface{}) interface{} {
    c.PacketWriter.QueuePacket(data)
    return <-c.callbacks[id]
}

现在这是我的问题:reader.parseBytes 函数执行一些密集的解码操作,创建了相当多的对象(GC 决定 运行)。 然而,GC 暂停了当前正在解码字节的 reader goroutine,然后挂起 here 描述了一个看起来与我相似的问题。我已经确认它实际上是 GC 引起的,因为 运行 与 GOGC=off 运行s 成功地结合了它。

此时,我的 3 个例程如下所示:
- Client (main routine):等待频道
- Writer: 还在运行ning,等待队列中的新数据
- Reader: 设置为运行nable,但实际上不是运行ning

不知何故,GC 要么无法停止所有例程以 运行,要么它在停止 goroutine 后不会恢复它们。

所以我的问题是:有什么方法可以解决这个问题吗?我是 Go 的新手,所以我真的不知道我的设计选择是否非常传统,我完全同意改变我的程序结构。我是否需要更改处理数据包读取回调的方式,是否需要尝试降低数据包解码器的强度?谢谢!

编辑:我正在 运行ning Go 1.5.1,我会在今天晚些时候尝试获得一个工作示例。

根据 mrd0ll4r 的评论,将作者更改为使用通道而不是切片(我什至不知道我一开始为什么这样做)。这似乎给了 GC 足够的 "mobility" 来允许线程停止。添加 runtime.Gosched() 并仍然使用切片也有效,但通道似乎更多 "go-esque".