2016-07-02 5 views
3

Я настраиваю цепочку из трех goroutines, каждая с входом выходного канала. Горотины будут считывать входной канал до тех пор, пока он не будет закрыт, увеличьте значение, отправьте его на выходной канал. Тем не менее, ниже программа тупиков с этим выходом:Почему эта программа Go зависает?

goroutine 'one': 1 
goroutine 'two': 2 
goroutine 'three': 3 
goroutine 'one': 10 
goroutine 'two': 11 
goroutine 'one': 100 
fatal error: all goroutines are asleep - deadlock! 

Код:

package main 

import (
    "fmt" 
) 

func int_channel(id string, i chan int, o chan int) { 
    defer close(o) 

    for x := range i { 
    fmt.Printf("goroutine '%s': %d\n", id, x) 
    o <- x + 1 
    } 

    fmt.Println("done") 
} 

func main() { 
    c0 := make(chan int) 
    c1 := make(chan int) 
    c2 := make(chan int) 
    c3 := make(chan int) 

    go int_channel("one", c0, c1) 
    go int_channel("two", c1, c2) 
    go int_channel("three", c2, c3) 

    c0 <- 1 
    c0 <- 10 
    c0 <- 100 
    c0 <- 1000 
    c0 <- 10000 
    c0 <- 100000 
    close(c0) 

    fmt.Println("Sent all numbers to c0") 

    for x := range c3 { 
    fmt.Printf("out: %d\n", x) 
    } 
} 

ответ

4

он висит, поскольку цикл, который считывает из выходного канала никогда не достигается, таким образом, каналы не «emptyed» и как только каждый канал имеет значение, записанное в него, прогресс не может быть достигнут, а программа зависает. Для того, чтобы исправить это написать на вход в другой goroutine, т.е.

func main() { 
    c0 := make(chan int) 
    c1 := make(chan int) 
    c2 := make(chan int) 
    c3 := make(chan int) 

    go int_channel("one", c0, c1) 
    go int_channel("two", c1, c2) 
    go int_channel("three", c2, c3) 

    go func(){ 
    c0 <- 1 
    c0 <- 10 
    c0 <- 100 
    c0 <- 1000 
    c0 <- 10000 
    c0 <- 100000 
    fmt.Println("Sent all numbers to c0") 
    close(c0) 
    }() 


    for x := range c3 { 
    fmt.Printf("out: %d\n", x) 
    } 
} 

IOW, когда линия c0 <- 1 выполняется, значение потоков Повсеместно все три cannels и заканчивается в c3, но так как цикл читатель еще не достиг , он просто «сидит там». Затем выполняется строка c0 <- 10, и это значение заканчивается на c2, потому что оно не может быть записано в c3 - предыдущее значение все еще там, блокируя запись. И, таким образом, когда выполняется линия c0 <- 100, все каналы заполнены и дальнейший прогресс невозможен.

+0

Кажется настолько очевидным сейчас :) Все еще привыкание к модели параллелизма Go. Благодаря! –

+0

Другой альтернативой было бы сделать буферизованный канал 'c0', с достаточной емкостью, чтобы принять все ваши первоначальные« набивки данных ». – Vatine

1

Вы не читали с c3 своевременно. Вы отправляете слишком много значений в c0. Таким образом, связь между каналами происходит так:

send 1 on c0 => recv 1 on c1 => send 2 on c2 => 
     recv 2 on c2 => send 3 on c3 => recv 3 on c3 

send 10 on c0 => recv 10 on c1 => send 11 on c2 => 
     recv 11 on c2 => send 12 on c3 -- // c3 still hasn't been read 
              // from and so send 
              // operation blocks here. 

c0, c1 и c2 продолжают получать, пока все их отправляет блок в конце концов. Вы можете обратиться к ответу @ ain ниже для решения.

Смежные вопросы