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

时间:2018-07-16 00:48:18

标签: go

我有以下内容,并且正在尝试进行一些并发的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 个答案:

答案 0 :(得分:3)

您不是在等待响应返回。这等效于:

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)
}