2015-12-14 102 views
5

我使用sync.WaitGroup, defer wg.Close()wg.Wait()等待我的goroutines完成。Golang应用程序使用sync.WaitGroup&通道永不退出

该程序等待,但它永远不会退出。

这是我的程序(可运行):

package main 

import (
    "fmt" 
    "io" 
    "log" 
    "net/http" 
    "os" 
    "sync" 
) 

var symbols = []string{ 
    "ASSA-B.ST", 
    "ELUX-B.ST", 
    "HM-B.ST", 
} 

func main() { 

    fmt.Println("fetching quotes...") 

    fetchedSymbols := make(chan string) 
    var wg sync.WaitGroup 
    wg.Add(len(symbols)) 

    for _, symbol := range symbols { 
     go fetchSymbol(symbol, &wg, fetchedSymbols) 
    } 

    for response := range fetchedSymbols { 
     fmt.Println("fetched " + response) 
    } 

    wg.Wait() 

    fmt.Println("done") 

} 

func fetchSymbol(symbol string, wg *sync.WaitGroup, c chan<- string) { 
    defer wg.Done() 
    resp, err := http.Get("http://ichart.yahoo.com/table.csv?s=" + symbol + "&a=0&b=1&c=2000") 
    defer resp.Body.Close() 

    if err != nil { 
     log.Fatal(err) 
    } 

    out, err := os.Create("./stock-quotes/" + symbol + ".csv") 
    defer out.Close() 

    if err != nil { 
     log.Fatal(err) 
    } 

    io.Copy(out, resp.Body) 
    c <- symbol 
} 

不应该当所有的报价已经被下载了这个程序退出? (仅供参考:我刚开始学习GO)

回答

13

你永远不会关闭fetchedSymbols通道,所以范围循环永远不会退出。

处理此问题的一种方法是使用WaitGroup,您必须发出信号指示何时关闭通道。对fetchedSymbols进行测距足以阻止主进程,并且不需要另一个通道或WaitGroup。

... 
go func() { 
    wg.Wait() 
    close(fetchedSymbols) 
}() 

for response := range fetchedSymbols { 
    fmt.Println("fetched " + response) 
} 

...