Тупик в программе при использовании диапазона на буферизованном канале - PullRequest
0 голосов
/ 25 апреля 2019

Я учусь Го и играю с Горутинами и каналами.Я писал очень изобретательный и наивный рабочий пул, используя два буферизованных канала, один для входов и один для выходов.

Теперь я закрываю свой входной канал после добавления к нему заданий и затем, наконец, читая выходной канал, чтобы прочитатьрезультаты, однако, когда я использовал for val := range ch для программы вывода паники с тупиком.Вот пример кода

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

Вот вывод, который я вижу

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

Я понимаю, что при использовании обычного for loop я получаю точное количество значений (9) который я изначально положил в jobs канал.Но разве for range не должен обрабатывать это автоматически, когда больше нет данных для чтения из канала, канал отправит значение false, и цикл прекратится?

1 Ответ

0 голосов
/ 26 апреля 2019

Решение этого было довольно очевидным, все, что мне нужно было сделать, это close выходной канал на рабочем месте, и range начал работать правильно по очевидным причинам.

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