2012-12-28 15 views
7

Uczę się Go i pracuję nad this lesson z GoTours. Oto, co mam do tej pory.Jak mogę złapać wyjątek z zakleszczeniem kanału?

package main 

import (
    "fmt" 
    "code.google.com/p/go-tour/tree" 
) 

// Walk walks the tree t sending all values 
// from the tree to the channel ch. 
func Walk(t *tree.Tree, ch chan int) { 
    if t != nil { 
     Walk(t.Left, ch) 
     ch <- t.Value 
     Walk(t.Right, ch) 
    } 
} 

func main() { 
    var ch chan int = make(chan int) 
    go Walk(tree.New(1), ch) 
    for c := range ch { 
     fmt.Printf("%d ", c)  
    } 
} 

Jak widać, próbuję przetestować moją funkcję Walk, drukując wartości, które napisałem na kanale. Jednak pojawia się następujący błąd.

1 2 3 4 5 6 7 8 9 10 throw: all goroutines are asleep - deadlock! 

goroutine 1 [chan receive]: 
main.main() 
    main.go:25 +0x85 

goroutine 2 [syscall]: 
created by runtime.main 
    /usr/local/go/src/pkg/runtime/proc.c:221 

exit status 2 

Ten błąd należy oczekiwać myślę, bo nigdy close kanał. Czy istnieje jednak sposób, w jaki mogę "złapać" ten błąd impasu i programowo go rozwiązać?

+2

definicji impas oznacza, że ​​wszystkie goroutines nie działają. Jeśli nic nie działa, nie ma goroutine, które może "złapać" wyjątek. – newacct

+0

Dzięki! Jeśli tak jest, czy istnieje sposób, aby przestać czytać z kanału po tym, jak przeczytałem 'n' liczbę razy, gdzie' n' jest liczbą razy zapisaną w kanale? – dangerChihuahua007

+2

Kolejna wskazówka: dobrze jest określić kierunek kanału w funkcji Spacer, tj. func Walk (t * tree.Tree, chan <- int) –

Odpowiedz

6

Zakleszczenie jest podobne do ujemnego wskaźnika, który reprezentuje BŁĄD w twoim programie. Ta klasa błędów zwykle nie jest możliwa do odzyskania z tego powodu.

Jak wspomniał lbonn, problem tutaj polega na tym, że musisz "zamknąć (myChan)" swój kanał. Jeśli nie zrobisz tego w pętli zasięgu, pętla będzie czekać na następny element na zawsze.

Można spróbować czegoś takiego:

func main() { 
    var ch chan int = make(chan int) 
    go func() { 
     Walk(tree.New(1), ch) 
     close(ch) 
    }() 
    for c := range ch { 
     fmt.Printf("%d ", c) 
    } 
} 

Jeśli chcesz przechodzić przez drzewo równolegle trzeba będzie dokonać dalszych zmian:

package main 

import (
    "code.google.com/p/go-tour/tree" 
    "fmt" 
    "sync" 
) 

// Walk walks the tree t sending all values 
// from the tree to the channel ch. 
func Walk(t *tree.Tree, ch chan int, done *sync.WaitGroup) { 
    if t != nil { 
     done.Add(2) 
     go Walk(t.Left, ch, done) //look at each branch in parallel 
     go Walk(t.Right, ch, done) 
     ch <- t.Value 
    } 
    done.Done() 
} 

func main() { 
    var ch chan int = make(chan int, 64) //note the buffer size 
    go func() { 
     done := new(sync.WaitGroup) 
     done.Add(1) 
     Walk(tree.New(1), ch, done) 
     done.Wait() 
     close(ch) 
    }() 
    for c := range ch { 
     fmt.Printf("%d ", c) 
    } 
} 
5

Nie, nie można wyleczyć z impasu.

+1

Dzięki! Ale w jaki sposób mogę wydrukować elementy wysłane do kanału? – dangerChihuahua007

7

To zakleszczenie, ponieważ konstrukcja range iteruje aż do zamknięcia kanału. http://golang.org/ref/spec#For_statements

W tym miejscu należy zamknąć kanał, gdy drzewo jest w pełni zbadane lub użyć innej konstrukcji.

Dla tego przykładu, wiesz, że drzewa mają rozmiar 10, więc możesz po prostu zrobić pętlę for od 1 do 10 i czytać z kanału raz w każdej iteracji.

Powiązane problemy