I'm experimenting with Go channels and have an issue where the simple program below does not terminate.
Essentially I want to make some async HTTP get requests and then wait till they are all finished. I'm using a buffered channel but I'm not sure this is the idiomatic way.
func GetPrice(quotes chan string) {
client := &http.Client{}
req, _ := http.NewRequest("GET", "https://some/api", nil)
req.Header.Set("Accept", "application/json")
res, err := client.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
quotes <- string(body)
}
func main() {
const max = 3
quotes := make(chan string, max)
for i := 0; i < max; i++ {
go GetPrice(quotes)
}
for n := range quotes {
fmt.Printf("\n%s", n)
}
}
The program successfully prints 3(max) items
{"price":"1.00"}
{"price":"2.00"}
{"price":"3.00"}
but then blocks and never exits.
sync.WaitGroup
can be used here to wait for all goroutines and then closing the quotes
channel:
func getPrice(quotes chan<- string, onExit func()) {
go func() {
defer onExit()
req, _ := http.NewRequest("GET", "https://some/api", nil)
req.Header.Set("Accept", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
panic(err) // should be handled properly
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
quotes <- string(body)
}()
}
func main() {
const max = 3
var wg sync.WaitGroup
quotes := make(chan string, max)
for i := 0; i < max; i++ {
wg.Add(1)
getPrice(quotes, func() { wg.Done() })
}
go func() {
defer close(quotes)
wg.Wait()
}()
for n := range quotes {
fmt.Printf("\n%s", n)
}
}