2012-11-12 48 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將不會等待任何仍存在的goroutine完成,而只是退出。

recv將在第一次「迭代」後返回主,並且因爲main沒有更多的事情要做,程序將終止。

一個解決這個問題是有信號,所有的工作就完成了一個通道,如下所示:

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 struct{}而不是chan bool將爲您節省一個額外的字節,因爲空結構不使用任何內存。

+4

對於信道數據類型不重要的信道,可以使用'chan struct {}'。一個空的結構不會佔用內存,同時仍然允許所需的行爲。而布爾值佔用一個字節。 – jimt

+1

是的,說實話我是爲了讓布爾變得更復雜。但是,一個空的結構在技術上更好。你想將其納入我的答案或我自己編輯它? :) –

+1

這是你的答案,去吧:) – jimt

10

A sync.Waitgroup是另一種解決方案,專門用於等待任意數量的goroutines運行其課程的目的。

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

你的第二個版本打印10,9,8,7,6,5,4,3,2,1?嘗試100次:D – vrbilgi

+1

@vrbilgi它沒有工作。我誤解了。感謝U.編輯。 ;) – rplaurindo