doupuxuan5784 2015-10-27 09:28
浏览 34
已采纳

去GC停止我的goroutine吗?

I have been trying to get into Go from the more traditional languages such as Java and C and so far I've been enjoying the well-thought out design choices that Go offers. When I started my first "real" project though, I ran into a problem that almost nobody seems to have.

My project is a simple networking implementation that sends and receives packets. The general structure is something like this (of course simplified):

A client manages the net.Conn with the server. This Clientcreates a PacketReaderand a PacketWriter. These both run infinite loops in a different goroutine. The PacketReader takes an interface with a single OnPacketReceived function that is implemented by the client.

The PacketReader code looks something like this:

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))
    }
}()

The PacketWriter code looks something like this:

go func() {

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

In order to make Client blocking, the client makes a channel that gets filled by OnPacketReceived, something like this:

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]
}

Now here is my problem: the reader.parseBytes function does some intensive decoding operation that creates quite a lot of objects (to the point that the GC decides to run). The GC however, pauses the reader goroutine that is currently decoding the bytes, and then hangs. A problem that seems similar to mine is described here. I have confirmed that it is actually the GC causing it, because running it with GOGC=off runs successfully.

At this point, my 3 routines look like this:
- Client (main routine): Waiting for channel
- Writer: Still running, waiting for new data in queue
- Reader: Set as runnable, but not actually running

Somehow, the GC is either not able to stop all routines in order to run, or it does not resume said goroutines after it stopped them.

So my question is this: Is there any way to fix this? I am new to Go so I don't really know if my design choices are even remotely conventional, and I'm all up with changing the structure of my program. Do I need to change the way I handle packet reading callbacks, do I need to try and make the packet decoder less intensive? Thanks!

Edit: I am running Go 1.5.1, I'll try to get a working example later today.

  • 写回答

1条回答 默认 最新

  • dorpbn1027 2015-10-27 12:34
    关注

    As per mrd0ll4rs comment, changed the writer to use channels instead of a slice (I don't even know why I did that in the first place). That seemed to give the GC enough "mobility" to allow the threads to stop. Adding in the runtime.Gosched() and still using slices also worked though, but the channels seemed more "go-esque".

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 Android STD快速启动
  • ¥15 如何使用simulink建立一个永磁同步直线电机模型?
  • ¥30 天体光谱图的的绘制并得到星表
  • ¥15 PointNet++的onnx模型只能使用一次
  • ¥20 西南科技大学数字信号处理
  • ¥15 有两个非常“自以为是”烦人的问题急期待大家解决!
  • ¥30 STM32 INMP441无法读取数据
  • ¥15 R语言绘制密度图,一个密度曲线内fill不同颜色如何实现
  • ¥100 求汇川机器人IRCB300控制器和示教器同版本升级固件文件升级包
  • ¥15 用visualstudio2022创建vue项目后无法启动