multithreading - 自同步 Goroutine 以死锁告终

原文 标签 multithreading go synchronization deadlock

我有一个压力测试问题,我想通过 Go 中的简单同步来解决。到目前为止,我已经尝试在我的特定用例中找到有关 Go 同步的文档,但没有找到任何适合的文档。

更具体一点:
我必须完成一项任务,我必须在主例程中启动大量线程(在此示例中仅用两个线程说明)。所有启动的worker都应该以无序的方式自己准备一些初始化 Action 。直到它们到达一小部分命令,我希望它们一次被所有 goroutine 执行,这就是为什么我想使 goroutine 彼此自我同步。对于我的任务来说,通过实例化所有其他 goroutine 的主例程的延迟不会影响工作线程执行的真正并行度(在注释中的标签 #maximum parallel 处),这一点非常重要。为此,我使用主例程中正在运行的 goroutine 数量初始化了一个 WaitGroup ,并将其传递给所有例程,以便它们可以同步彼此的工作流。

代码看起来类似于这个例子:

import sync

func worker_action(wait_group *sync.WaitGroup) {
    // ...
    // initialization
    // ...

    defer wait_group.Done() 
    wait_group.Wait() // #label: wait

    // sequence of maximum parallel instructions // #label: maximum parallel

    // ...
}

func main() {
    var numThreads int = 2 // the number of threads shall be much higher for the actual stress test

    var wait_group sync.WaitGroup
    wait_group.Add(numThreads)
    for i := 0; i < numThreads; i++ {
        go worker_action(&wait_group)
    }

    // ...
}

不幸的是,一旦所有 goroutine 都到达 Wait 指令(在注释中用 #wait 标记),我的设置就会陷入僵局。对于我从主例程开始的任何数量的线程都是如此(即使两个线程很快陷入死锁)。

从我的角度来看,死锁不应该发生,因为在等待指令之前,每个 goroutine 在同一个 WaitGroup 上执行完成的函数。

我对 WaitGroup 的工作方式有错误的理解吗?例如,是否不允许在主例程以外的 goroutine 中执行等待函数?或者有人可以给我提示我还缺少什么吗?

非常感谢您提前。

编辑:

非常感谢@tkausl。确实是不必要的“延迟”导致了问题。我不知道我自己怎么看不到它。

最佳答案

您的代码中有几个问题。先说表格。惯用的 Go 应该使用驼峰式命名法。 wg是 WaitGroup 的更好名称。

但更重要的是在您的代码等待的地方使用。不在你的 Goroutines 中。它应该在主函数中等待:

func workerAction(wg *sync.WaitGroup) {
    // ...
    // initialization
    // ...

    defer wg.Done() 
    // wg.Wait() // #label: wait

    // sequence of maximum parallel instructions // #label: maximum parallel

    // ...
}

func main() {
    var numThreads int = 2 // the number of threads shall be much higher for the actual stress test

    var wg sync.WaitGroup
    wg.Add(numThreads)
    for i := 0; i < numThreads; i++ {
        go workerAction(&wg)
    }
    wg.Wait() // you need to wait here

    // ...
}

关于multithreading - 自同步 Goroutine 以死锁告终,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53127050/

相关文章:

php - 同步本地和远程数据库

go - 可以将 golang channel 绑定(bind)到模板中

oracle - 获取最后插入的 id (go + oracle)

java - Java 中的 IllegalMonitorStateException

java - 在多线程环境中设置对象字段

go - 如何查找两个 slice 是否是对同一内存的引用?

c - 'file data' 和 'file size' 是一起还是分别提交到磁盘

java - 如何扩展Hibernate Readers?

c++ - WaitForSingleObject()

multithreading - future 与线程 : Which is better for working with channels in core. 异步?