简体   繁体   中英

Deadlock in the program when using for range on buffered channel

I am learning Go and was playing with Goroutines and channels. I was writing a very contrived and naive workerpool using two buffered channels one for inputs and one for outputs.

Now I am closing my inputs channel after I add jobs to it and then reading the output channel finally to read the results from it, however when I used for val := range ch for the output program panics with a deadlock. Here is the sample code

package main

import (
    "fmt"
    "time"
)

func main() {
    st := time.Now()

    jobs := make(chan int, 100)
    res := make(chan int, 100)

    // Putting items to the jobs channel
    for i := 0; i < 9; i++ {
        jobs <- i
    }
    close(jobs)

    go workerPool(jobs, res, 1)


    // This causes the program to panic with deadlock
    for v := range res {
        fmt.Println(v)
    }

// This works just fine and program does not panics
    //for i := 0; i < 9; i++ {
    //  fmt.Println(<-res)
    //}

    ed := time.Now()
    fmt.Println(ed.Sub(st))
}

func workerPool(ip <-chan int, op chan<- int, id int) {
    for v := range ip {
        fmt.Println("Worker", id, "working on ", v)
        op <- 1
    }
}

Here is the output I see

Worker 1 working on  0
Worker 1 working on  1
Worker 1 working on  2
Worker 1 working on  3
Worker 1 working on  4
Worker 1 working on  5
Worker 1 working on  6
Worker 1 working on  7
Worker 1 working on  8
1
1
1
1
1
1
1
1
1
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()

I understand that when I use the conventional for loop I am fetching the exact number of values (9) which I initially put into jobs channel. But isn't for range supposed to handle this automatically that when there is no more data to be read from the channel, the channel will send the false value and the loop will terminate ?

The solution to this was pretty obvious, all I had to do was close the outputs channel in the worker and range started working correctly for obvious reasons.

func workerPool(ip <-chan int, op chan<- int, id int) {
    for v := range ip {
        fmt.Println("Worker", id, "working on ", v)
        op <- fib(v)
    }
    close(op) // change made 
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM