首页 > 解决方案 > 如何关闭频道并等待多个 http 响应?

问题描述

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

而它也应该打印响应。

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

标签: go

解决方案


您无需等待回复返回。这相当于:

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
}

相反,您可以使用 async.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)
}

推荐阅读