2012-11-12 24 views
10

私は数日前に言語を学び始めました。私はいくつかの楽しいコードを書くことを試みたとき、私は奇妙な動作で立ち往生しています。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のみが出力されます。 recvに電話する前にgoを削除すると、100が印刷されます。私はここに日課を悪用していると信じていますが、なぜこのようにルーチンが失敗するのか理解できません。

答えて

15

メイン関数が戻るとき、Goは既存のゴルーチンが終了するのを待つのではなく、終了するだけです。

recvは、最初の "反復"の後にメインに戻ります。メインに何もする必要がないため、プログラムは終了します。この問題への

一つの解決策は、以下のように、すべての作業が行われていることを知らせるチャネルを持つことです。

ここ
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はほんの一例です。より効率的にするには、chan boolの代わりにchan struct{}を使用すると、空の構造体にはメモリが使用されないため、追加のバイトが節約されます。

+4

チャネルのデータタイプが重要でない信号チャネルの場合、 'chan struct {}'を使用できます。空の構造体はメモリを消費しませんが、依然として望ましい動作を可能にします。一方、ブール値は1バイトを占めます。 – jimt

+1

ええ、正直言って、私はそれをもう複雑にしないためにブールに行きました。しかし、ええ、空の構造体は技術的に優れています。それを私の答えに取り入れたいのですか、自分で編集しますか? :) –

+1

それはあなたの答えです。 – jimt

10

sync.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() 
} 
-2

私はそうし、また働いた。どうして?

package main 

import "fmt" 

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

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

func main() { 
    recv(10) 
} 
+0

2番目のバージョンは10,9,8,7,6,5,4,3,2,1を印刷しましたか? 100回試してください:D – vrbilgi

+1

@vrbilgi動作しませんでした。私は間違っていた。ありがとうございました。 ;) – rplaurindo