Golang应用程序使用sync.WaitGroup和通道永远不会退出。

huangapple go评论71阅读模式
英文:

Golang app using sync.WaitGroup & channels never exits

问题

我使用sync.WaitGroupdefer wg.Close()wg.Wait()来等待我的goroutine完成。

程序确实等待,但它从未退出。

这是我的可运行程序:

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)

英文:

I use sync.WaitGroup, defer wg.Close() and wg.Wait() to wait for my goroutines to complete.

The program do wait, but it never exits.

This is my program (runnable):

package main

import (
	&quot;fmt&quot;
	&quot;io&quot;
	&quot;log&quot;
	&quot;net/http&quot;
	&quot;os&quot;
	&quot;sync&quot;
)

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

func main() {

	fmt.Println(&quot;fetching quotes...&quot;)

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

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

	for response := range fetchedSymbols {
		fmt.Println(&quot;fetched &quot; + response)
	}

	wg.Wait()

	fmt.Println(&quot;done&quot;)

}

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

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

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

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

	io.Copy(out, resp.Body)
	c &lt;- symbol
}

Shouldn't this program exit when all the quotes have been downloaded? (FYI: I just started learning GO)

答案1

得分: 15

你从未关闭fetchedSymbols通道,因此该循环将永远不会退出。

处理这个问题的一种方法是使用已经存在的WaitGroup来信号何时关闭通道。在fetchedSymbols上进行范围循环足以阻塞主程序的进展,你不需要另一个通道或WaitGroup。

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

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

You're never closing the fetchedSymbols channel, so that range loop will never exit.

One way to handle this is to use use the WaitGroup you already have to signal when to close the channel. Ranging over fetchedSymbols is enough to block the progress in main, and you don't need another channel or WaitGroup.

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

for response := range fetchedSymbols {
	fmt.Println(&quot;fetched &quot; + response)
}

...

huangapple
  • 本文由 发表于 2015年12月15日 06:03:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/34277464.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定