12

私は数日前にgo言語を学び始めました。楽しいコードを書き始めようとしたとき、奇妙な動作に行き詰まりました。

package main

import "fmt"

func recv(value int) {
    if value < 0 {
        return
    }

    fmt.Println(value)
    go recv(value-1)
}

func main() {
    recv(10)
}

上記のコードを実行すると、のみ10が出力されます。へgoの呼び出しの前に を削除するとrecv、が出力されます。ここで go ルーチンを誤用していると思いますが、なぜこの方法で go ルーチンを開始できなかったのか理解できません。100

4

3 に答える 3

16

メイン関数が戻ると、Go はまだ存在するゴルーチンが終了するのを待たずに、ただ終了します。

recv最初の「繰り返し」の後に main に戻り、main はそれ以上何もすることがないため、プログラムは終了します。

この問題の解決策の 1 つは、次のように、すべての作業が完了したことを通知するチャネルを用意することです。

package main

import "fmt"

func recv(value int, ch chan bool) {
    if value < 0 {
        ch <- true
        return
    }

    fmt.Println(value)
    go recv(value - 1, ch)
}

func main() {
    ch := make(chan bool)
    recv(10, ch)

    <-ch
}

ここでrecvは、戻る前に単一のブール値mainを送信し、チャネルでそのメッセージを待ちます。

プログラムのロジックでは、使用する型や特定の値は重要ではありません。booltrueは単純な例です。より効率的にしたい場合は、 a のchan struct{}代わりに aを使用するchan boolと、追加のバイトを節約できます。空の構造体はメモリをまったく使用しないためです。

于 2012-11-12T04:19:27.413 に答える
10

Async.Waitgroupは別の解決策であり、任意の量のゴルーチンがコースを実行するのを待つことを特に目的としています。

package main

import (
    "fmt"
    "sync"
)

func recv(value int, wg *sync.WaitGroup) {
    if value < 0 {
        return
    }

    fmt.Println(value)

    wg.Add(1) // Add 1 goroutine to the waitgroup.

    go func() {
        recv(value-1, wg)
        wg.Done() // This goroutine is finished.
    }()
}

func main() {
    var wg sync.WaitGroup
    recv(10, &wg)

    // Block until the waitgroup signals
    // all goroutines to be finished.
    wg.Wait()
}
于 2012-11-13T11:21:12.357 に答える