什么会导致代码阻塞?

时间:2013-10-27 09:06:19

标签: concurrency go

由于go是并发程序语言,并使用channel(我几乎使用它所有代码)或其他内容来同步goroutine

而且我也知道要使用调度程序来安排goroutine,这意味着你应该在每个goroutine中调用scheduler(通道操作,runtime.goSche或其他)并保证它会被执行。

以上是go的所有限制,我用它来设计我的代码。

但我也发现在我的代码中会发生代码阻塞。并且很难找到阻塞的原因(甚至使用 GDB )。

我错过了什么吗?

还有什么可能导致阻止?

我应该注意什么?

[编辑] :好的,因为我项目的代码有点大。我决定不显示标准 go代码,只是可能导致代码阻塞的部分的一般概念。以下是我项目中文件传输模块的一些代码:

func(c *client)listenRead() {
    for {
        _ := websocket.JSON.Receive(c.ws, &package)
        switch package.Op {
        case fileUpld:
            c.fileMan.store <- package.Body
        case fileDownld:
            c.fileMan.downld <- package.Body
        case c.xxx:
            ...
        default:
            // bad package.
        }
    }
}

客户端通过来自其他客户端的websocket收听和接收消息,然后根据package的{​​{1}}字段将包转发给不同的处理程序,例如Op如下所示。

fileManager

当{strong> chan func(fm *fileManager) fileRouter() { for { select { case fs := <-fm.fileUpld: if window < filesize { f.Write(fs.content) // client A write to file window += fs.contSize } else { f.close() // close file } case fd := fm.downld: go fm.downldFile(fd) } } } 获取从fileManger发送的数据时,fileUpld可以接收文件并存储到服务器。它可以在从客户端收到client时下载文件,并生成request来完成工作,如下所示:

goroutine

我的文件传输模块的主要想法是客户端A 想要将文件发送到客户端B ,并且不希望等待来自客户端B func(fm *fileManager) downldFile(fd) { f := getFile(fd) // get the file that client A write b := make([]byte, SeqLength) for { if convergence < window { f.Read(b) // wrap 'b' to package 'p', for send fm.server.send <- p // send to client B } else if window < fileSize { runtime.Goshed() } else { // download done. fm.done <- xx return } } } ,这意味着它将首先存储到服务器,然后客户端B 将通过从服务器下载来获取该文件。但客户端B 可能会在客户端A 上传文件时下载文件。因此上传和下载之间需要同步。

我使用三个变量来实现此目的:窗口收敛 filesize 。当客户端A 上传(写入)文件时,窗口会增加它写入的字节的值。当客户端B 下载(读取)文件时,收敛将增加它读取的字节数。 acceptance只发生Writewindow < filesize仅发生read。就像:

convergence < window

我知道这会导致数据争用,但它也保证+-----------+---------------+--------------+ |############|||||||||||||||| | +-----------+---------------+--------------+ ^ ^ ^ | | | convergence window filesize 不会读取read尚未写入的内容。( BTW :我没有使用write来实现它的解决方案。)

当我尝试同时上传和下载时,会发生代码阻塞(我放慢客户端A 来实现它)。但是当我将channel设置为2时,它没有问题。

1 个答案:

答案 0 :(得分:0)

你应该考虑一个垃圾收集器来暂停整个程序,所谓的“停止世界”。在具有大内存消耗的大型应用程序中,GC可以“停止世界”长达10秒,但这是最糟糕的情况。以下是Go中关于GC的一个很好的答案:What kind of Garbage Collection does Go use?