Search code examples
gogoroutine

Golang - Why use done channel


It's one of example code of Golang. But cannot understand why 'done' channel need in this case.

https://gobyexample.com/closing-channels

There is no reason to sent true to done channel. We can know jobs channel is done when "sent all jobs" message is printed, isn't it?

I deleted code that relative to done channel and result is still same.

https://play.golang.org/p/xOmzobFpTQ


Solution

  • No the result is not the same:
    Your main goroutine exits before your received job goroutine in many situations (e.g. different CPU loads, and it is nondeterministic and system dependent behavior), so in that way you cannot guarantee that all jobs received, e.g. just Add

    time.Sleep(500)
    

    before

    fmt.Println("received job", j)
    

    to see this, try it on The Go Playground:

    // _Closing_ a channel indicates that no more values
    // will be sent on it. This can be useful to communicate
    // completion to the channel's receivers.
    
    package main
    
    import (
        "fmt"
        "time"
    )
    
    // In this example we'll use a `jobs` channel to
    // communicate work to be done from the `main()` goroutine
    // to a worker goroutine. When we have no more jobs for
    // the worker we'll `close` the `jobs` channel.
    func main() {
        jobs := make(chan int, 5)
        //done := make(chan bool)
    
        // Here's the worker goroutine. It repeatedly receives
        // from `jobs` with `j, more := <-jobs`. In this
        // special 2-value form of receive, the `more` value
        // will be `false` if `jobs` has been `close`d and all
        // values in the channel have already been received.
        // We use this to notify on `done` when we've worked
        // all our jobs.
        go func() {
            for {
                j, more := <-jobs
                if more {
                    time.Sleep(500)
                    fmt.Println("received job", j)
                } else {
                    fmt.Println("received all jobs")
                    //done <- true
                    return
                }
            }
        }()
    
        // This sends 3 jobs to the worker over the `jobs`
        // channel, then closes it.
        for j := 1; j <= 3; j++ {
            jobs <- j
            fmt.Println("sent job", j)
        }
        close(jobs)
        fmt.Println("sent all jobs")
    
        // We await the worker using the
        // [synchronization](channel-synchronization) approach
        // we saw earlier.
        //<-done
    }
    

    output:

    sent job 1
    sent job 2
    sent job 3
    sent all jobs
    

    instead of:

    sent job 1
    received job 1
    received job 2
    sent job 2
    sent job 3
    received job 3
    received all jobs
    sent all jobs
    

    See:
    Goroutine does not execute if time.Sleep included
    Why is time.sleep required to run certain goroutines?
    Weird channel behavior in go