I am playing with channels and don't quite understand why the code I wrote becomes unreachable at this point and also a deadlock arises. Shouldn't the select take the value from the quit channel and then exit from the infinite for loop?
func run(jobs []Job, receive, quit chan int) {
for _, job := range jobs {
go func(job Job) {
receive <- longCalculation(job)
}(job)
}
quit <- -1 // write to the channel to signal end of work
}
func main() {
rand.Seed(time.Now().UnixNano())
jobs := makeJobs()
receive := make(chan int)
quit := make(chan int)
run(jobs, receive, quit)
var sum int
for {
select {
case data := <-receive:
sum = data
case <-quit: // take the last value indicating end of work
fmt.Println("Exiting for loop ...", quit)
return
}
}
fmt.Print(sum) -> this line says unreachable code
}
CodePudding user response:
for {
select {
case data := <-receive:
sum = data
case <-quit: // take the last value indicating end of work
fmt.Println("Exiting for loop ...", quit)
return
}
}
Change it into
running := true
for running {
select {
case data := <-receive:
sum = data
case <-quit: // take the last value indicating end of work
fmt.Println("Exiting for loop ...", quit)
running = false
break
}
}
It's because the function stop immediately when you return
CodePudding user response:
You can just use a single channel & close it to signal you are done:
func run(jobs []Job, receive chan int) {
var wg sync.WaitGroup
wg.Add(len(jobs))
for _, job := range jobs {
go func(job Job) {
defer wg.Done()
receive <- longCalculation(job)
}(job)
}
wg.Wait()
close(receive)
}
This simplifies your read-side logic:
func main() {
// ....
go run(jobs, receive)
var sum int
for data := range receive {
sum = data
}
fmt.Print(sum)
}