7

私は Go を学んでおり、GoTours からこのレッスンに取り組んでいます。これが私がこれまでに持っているものです。

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

ご覧のとおり、チャネルに書き込んだ値を出力して、Walk 関数をテストしようとしています。ただし、次のエラーが発生します。

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

このエラーは、私closeがチャネルを使用したことがないため、予想されるはずです。ただし、このデッドロック エラーを「キャッチ」してプログラムで処理する方法はありますか?

4

5 に答える 5

8

rangeチャネルが閉じられるまで構造が繰り返される ため、これはデッドロックになります。http://golang.org/ref/spec#For_statements

ここでは、ツリーが完全に探索されたらチャネルを閉じるか、別の構成を使用する必要があります。

この例では、ツリーのサイズが 10 であることがわかっているため、単純に 1 から 10 までの for ループを実行し、反復ごとに 1 回チャネルから読み取ることができます。

于 2012-12-29T04:39:47.917 に答える
8

デッドロックは、プログラムのバグを表す nil ポインターの参照に似ています。このクラスのエラーは通常、この理由から回復できません。

lbonn が述べたように、ここでの問題は、チャンネルを「閉じる (myChan)」必要があることです。これを for-range ループで行わないと、ループは次の要素を永久に待機します。

次のようなことを試すことができます:

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

ツリーを並行してトラバースする場合は、さらに変更を加える必要があります。

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)
    }
}
于 2012-12-30T00:04:13.160 に答える
6

いいえ、デッドロックから回復することはできません。

于 2012-12-28T21:08:42.330 に答える
0

チャネルのデッドロック エラーは次のとおりです。

致命的なエラー: すべてのゴルーチンがスリープ状態です - デッドロック!

チャネルのデッドロックはpanicエラーではなく、致命的なエラーです。https://golang.org/pkg/log/#Fatalを参照してください

Fatal は、Print() の後に os.Exit(1) を呼び出すことと同等です。

ご覧のとおり、は最後にFatal呼び出すos.Exit(1)ので、 とはまったく異なりpanicます。recover

于 2019-10-14T14:31:25.837 に答える