-1

由于 go 是一种并发程序语言并使用channel(我几乎所有代码都使用它)或其他东西来同步goroutine

而且我也知道 go 使用调度器来调度goroutine,这意味着你应该scheduler在每个 goroutine 中调用(通道操作、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'Op字段将包转发到不同的处理程序,例如,fileManager如下所示。

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

当chan获取从 发送的数据时, AfileManger可以接收文件片段并存储到服务器。当它收到来自客户端的文件时,它可以下载文件,它会生成一个来完成这项工作,如下所示: fileUpldclientrequestgoroutine

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

我的文件传输模块的主要思想是客户端 A想要向客户端 B发送文件,并且不想等待acceptance来自客户端 B,这意味着它将首先存储到服务器,客户端 B稍后将通过从服务器下载。但是客户端 B可能会在客户端 A上传文件时下载文件。所以上传和下载之间需要同步。

我使用三个变量来实现这一点:windowconvergencefilesize。当客户端A上传(写入)文件时,窗口将增加它写入的字节的值。当客户端 B下载(读取)文件时,收敛会增加它读取的字节数。Write仅发生window < filesizeread仅发生convergence < window。就像:

+-----------+---------------+--------------+
|############||||||||||||||||              |
+-----------+---------------+--------------+
            ^               ^              ^
            |               |              |
       convergence        window        filesize

我知道这会导致数据竞争,但它也保证read不会读取write尚未写入的内容。(顺便说一句:我没有channel用于实现它的解决方案。)

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

4

1 回答 1

0

您应该考虑使用垃圾收集器来暂停您的整个程序,即所谓的“停止世界”。在具有大量内存消耗的大型应用程序上,GC 最多可以“停止世界”10 秒,但这是最坏的情况。这是关于 Go 中 GC 的一个很好的答案:Go 使用什么样的垃圾收集?

于 2013-10-27T09:17:40.567 回答