去 GC 停止我的 goroutine?

标签 go garbage-collection

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

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

客户端管理与服务器的net.Conn。此 Client 创建一个 PacketReader 和一个 PacketWriter。它们都在不同的 goroutine 中运行无限循环。 PacketReader 接受一个接口(interface),其中包含一个由客户端实现的 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 填充的 channel ,如下所示:

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 会暂停当前正在解码字节的读取器 goroutine,然后挂起。描述了一个与我的问题相似的问题 here .我已经确认它实际上是 GC 引起的,因为使用 GOGC=off 运行它会成功运行。

此时,我的 3 个例程如下所示:
- 客户端(主例程):WAITING channel
- Writer: 仍在运行,等待队列中的新数据
- Reader:设置为可运行,但实际上并未运行

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

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

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

最佳答案

根据 mrd0ll4r s 评论,将作者更改为使用 channel 而不是 slice (我什至不知道为什么我首先这样做)。这似乎为 GC 提供了足够的“机动性”以允许线程停止。添加 runtime.Gosched() 并仍然使用 slice 也可以,但 channel 似乎更“go-esque”。

关于去 GC 停止我的 goroutine?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33364138/

相关文章:

Go 语言模板 : always quotes a string and removes comments

c - CGO对“TIFFGetField”的 undefined reference

java - 与垃圾收集语言一起使用时,哪种代码的 CPU/内存效率更高?

java - G1 gc 上 "Ext Root Scanning"的文档/代码/详细说明?

linux - 您可以在 Go 中运行程序的独立实例吗?

unit-testing - 如何在同一结构中的另一个方法中调用 stub 方法

java - 为什么 JVM 的设计方式不允许强制垃圾收集?

.net - 将对象固定在 LOH 中是否会影响 GC 性能?

c# - .Net4 中的 GC : Specifying gcServer and gcConcurrent together

linux - 在 Go 中执行 Shell/Bash