For loop with buffered channel

10,537

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)
    }
}
Share:
10,537
Ayub Malik
Author by

Ayub Malik

Updated on June 04, 2022

Comments

  • Ayub Malik
    Ayub Malik almost 2 years

    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.

  • Ayub Malik
    Ayub Malik over 6 years
    I'm going to go for this answer as it logically represents what I'm trying to do.
  • L_J
    L_J over 5 years
    While this code may answer the question, providing information on how and why it solves the problem improves its long-term value.
  • jibeeeee
    jibeeeee over 3 years
    According to the documentation, higher-level synchronization is better done via channels and communication. It can be a solution for using chans