Home > Mobile >  Golang worker using wait groups
Golang worker using wait groups

Time:10-28

I'm new to Golang and trying to understand how WaitGroups and concurrency in Golang works. In this example, 5 workers are created with a channel for passing a job to each worker. The workers are made to sleep for 1 second to simulate a heavy computation. All goes well, but the program does not quit gracefully. Instead this error message is printed. Please help understand why this happens.

fatal error: all goroutines are asleep - deadlock!

This is the code,


import (
    "fmt"
    "sync"
    "time"
)

func worker(wg *sync.WaitGroup, messageChannel <-chan string) {
    defer wg.Done()
    for i := range messageChannel {
        time.Sleep(time.Second)
        fmt.Println("done processing - ", i)
    }
}

func stop(wg *sync.WaitGroup) {
    fmt.Println("waiting on the main thread")
    wg.Wait()
}

func main() {
    wg := new(sync.WaitGroup)
    messageChannel := make(chan string, 50)

    // create workers
    for i := 0; i < 5; i   {
        wg.Add(1)
        go worker(wg, messageChannel)
    }

    // input some messages
    for i := 0; i < 10; i   {
        messageChannel <- fmt.Sprint(i)
    }

    stop(wg)
    close(messageChannel)
}

Thanks in advance!

CodePudding user response:

To expand a bit on @Peter's comment, here is the execution flow of the code that you wrote:

  • After initialization, you start your worker goroutines. Each worker goroutine will range over messageChannel, with a time delay of 1 second will print out a message.
  • Next, you insert some message in messageChannel through a for-loop. Each available worker goroutine receives a message until all messages are processed and printed out. After that, the worker goroutines are waiting for new messages to come from the messageChannel.
  • After your for-loop for inserting messages in the messageChannel is completed, you execute the stop function, which blocks on wg.Wait() and waits for all wg.Done() calls to be executed in all worker goroutines. However, since messageChannel is not closed, none of the worker goroutines can finish execution and none of the wg.Done() calls are executed.
  • The worker goroutines are stuck because the messageChannel never closes, the main goroutine is stuck because of the wg.Wait() call inside the stop function, and you end up with a deadlock where all goroutines are asleep.

Per suggestion, you just need to swap places for stop and close calls

//rest of the code
close(messageChannel)
stop(wg)

This way, when all messages are inserted in the messageChannel, you call close(messageChannel) and then stop(wg), which blocks on the wg.Wait call. The close(messageChannel) call ensures that, once all messages are read from the messageChannel, for-range loops on the messageChannel inside the worker goroutines will exit, and all defer wg.Done() calls will be executed. Once this happens, wg.Wait() will unblock and the program will finish execution properly.

  • Related