自同步Goroutines以死锁结束

时间:2018-11-02 23:42:35

标签: multithreading go synchronization deadlock

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

更具体一点: 我必须完成一项必须在主例程中启动大量线程(在此示例中仅显示了两个线程)的任务。所有发起的工作人员都应该自己以无序的方式准备一些初始化操作。在它们到达一小段命令之前,我希望它们立即由所有goroutine执行,这就是为什么我要彼此自动同步goroutine的原因。对于我的任务而言,至关重要的是,实例化所有其他goroutine的主例程的延迟不会影响工人执行的真正并行性(在注释中标记为#maximum parallel)。为此,我确实使用主例程中正在运行的goroutine的数量来初始化一个等待组,并将其传递给所有例程,以便它们可以彼此同步。

代码看起来类似于以下示例:

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都在同一等待组上立即执行完了函数,因此不应出现死锁。

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

非常感谢您。

编辑:

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

2 个答案:

答案 0 :(得分:0)

您的代码中有几个问题。首先是表格。成语Go应该使用camelCase。 wg是WaitGroup的更好称呼。

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

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

    // ...
}

答案 1 :(得分:-1)

再次感谢@tkausl。通过从行中删除不必要的“延迟”指令来解决该问题,该指令旨在使辅助goroutine增加完成的线程数。

即“ defer wait_group.Done()”->“ wait_group.Done()”