代码之家  ›  专栏  ›  技术社区  ›  user_78361084

如何关闭通道并等待多个http响应?

go
  •  0
  • user_78361084  · 技术社区  · 6 年前

    我有以下内容,正在尝试进行一些并发http调用,以便加快整个程序的速度,而不是逐个执行每个调用:

    package main
    
    import (
        "fmt"
        "net/http"
        "time"
    )
    
    type U struct {
        u    string
        name string
        resp *http.Response
    }
    
    func main() {
        urls := []*U{
            &U{"example", "http://www.example.com", nil},
            &U{"yahoo", "http://www.yahoo.com", nil},
            &U{"google", "http://www.google.com", nil},
        }
    
        ch := make(chan *U)
    
        // read from the channel
        go func() {
            for c := range ch {
                for i, u := range urls {
                    if c.name == u.name {
                        urls[i] = c
                    }
                }
            }
        }()
    
        // fetch the stuff
        for _, u := range urls {
            go func(u *U) {
                var err error
                u, err = getResponse(u)
                if err != nil {
                    fmt.Println(err)
                }
                ch <- u
            }(u)
        }
    
        for i, u := range urls {
            fmt.Println(i, u.resp) // all nil
        }
    }
    
    func getResponse(u *U) (*U, error) {
        c := &http.Client{
            Timeout: 10 * time.Second,
        }
    
        var err error
        u.resp, err = c.Get(u.u)
    
        return u, err
    }
    

    https://play.golang.org/p/Zko8xkEqDMB

    我可不想做一件事情

    0 <nil>
    1 <nil>
    2 <nil>
    

    但它也应该打印响应。

    我该如何确保我等到一切都完成后才能继续前进?好啊。谢谢。

    1 回复  |  直到 6 年前
        1
  •  3
  •   Adam Smith jeffpkamp    6 年前

    你不是在等待回复。这相当于:

    urls := []*U{
        &U{"example", "http://www.example.com", nil},
        &U{"yahoo", "http://www.yahoo.com", nil},
        &U{"google", "http://www.google.com", nil},
    }
    
    for i, u := range urls {
        fmt.Println(i, u.resp) // all nil
    }
    

    相反,你可以用 sync.WaitGroup 要确保在显示响应之前完成所有工作,请执行以下操作:

    var wg sync.WaitGroup
    
    for _, u := range urls {
        wg.Add(1)  // Add job to the waitgroup
        go func(u *U) {
            var err error
            u, err = getResponse(u)
            if err != nil {
                fmt.Println(err)
            }
            ch <- u
            wg.Done()  // Note when the job is done
        }(u)
    }
    
    wg.Wait()  // wait until all the Add'd jobs are Done'd
    for i, u := range urls {
        fmt.Println(i, u.resp) // all nil
    }
    

    或者您可以在同一个链中处理打印响应 getResponse 以下内容:

    for _, u := range urls {
        go func(u *U) {
            var err error
            u, err = getResponse(u)
            if err != nil {
                fmt.Println(err)
            }
            printResponse(u)  // implement printResponse however
            ch <- u
        }(u)
    }