自同步Goroutines以死锁结束

I have a stress test issue that I want to solve with simple synchronization in Go. So far I have tried to find documenation on my specific usecase regarding synchronization in Go, but didn't find anything that fits.

To be a bit more specific: I must fulfill a task where I have to start a large amount of threads (in this example only illustrated with two threads) in the main routine. All of the initiated workers are supposed to prepare some initialization actions by themselves in unordered manner. Until they reach a small sequence of commands, which I want them to be executed by all goroutines at once, which is why I want to self-synchronize the goroutines with each other. It is very vital for my task that the delay through the main routine, which instantiates all other goroutines, does not affect the true parallelism of the workers execution (at the label #maximum parallel in the comment). For this purpose I do initialize a wait group with the amount of running goroutines in the main routine and pass it over to all routines so they can synchronize each others workflow.

The code looks similar to this example:

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

    // ...
}

Unfortunately my setup runs into a deadlock, as soon as all goroutines have reached the Wait instruction (labeled with #wait in the comment). This is true for any amount of threads that I start with the main routine (even two threads are caught in a deadlock within no time).

From my point of view a deadlock should not occur, due to the fact that immediately before the wait instruction each goroutine executes the done function on the same wait group.

Do I have a wrong understanding of how wait groups work? Is it for instance not allowed to execute the wait function inside of a goroutine other than the main routine? Or can someone give me a hint on what else I am missing?

Thank you very much in advance.

EDIT:

Thanks a lot @tkausl. It was indeed the unnecessary "defer" that caused the problem. I do not know how I could not see it myself.

Again thanks @tkausl. The issue was resolved by removing the unnecessary "defer" instruction from the line that was meant to let the worker goroutines increment the number of finished threads.

I.e. "defer wait_group.Done()" -> "wait_group.Done()"

There are several issues in your code. First the form. Idiomatic Go should use camelCase. wg is a better name for the WaitGroup.

But more important is the use where your code is waiting. Not inside your Goroutines. It should wait inside the main func:

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

    // ...
}