在Go中,并行执行客户端请求相对简单。 在下面示例中,我们将使用客户端使用Go缓冲通道执行多个URL请求。 响应和错误都将转到一个单独的通道,任何有权访问客户端的人都可以轻松访问。
在本节中,创建客户端,读取通道以及处理响应和错误都将在main.go文件中完成。
实践
建立 config.go:
package async
import "net/http"
// NewClient 建立一个新的client并为其分配通道
func NewClient(client *http.Client, bufferSize int) *Client {
respch := make(chan *http.Response, bufferSize)
errch := make(chan error, bufferSize)
return &Client{
Client: client,
Resp: respch,
Err: errch,
}
}
type Client struct {
*http.Client
Resp chan *http.Response
Err chan error
}
// AsyncGet 执行Get然后将resp/error返回到适当的通道
func (c *Client) AsyncGet(url string) {
resp, err := c.Get(url)
if err != nil {
c.Err <- err
return
}
c.Resp <- resp
}
建立 exec.go:
package async
// FetchAll 遍历请求所有的url
func FetchAll(urls []string, c *Client) {
for _, url := range urls {
go c.AsyncGet(url)
}
}
建立 main.go:
package main
import (
"fmt"
"net/http"
"github.com/agtorre/go-cookbook/chapter6/async"
)
func main() {
urls := []string{
"https://www.google.com",
"https://golang.org",
"https://www.github.com",
}
c := async.NewClient(http.DefaultClient, len(urls))
async.FetchAll(urls, c)
for i := 0; i < len(urls); i++ {
select {
case resp := <-c.Resp:
fmt.Printf("Status received for %s: %d\n", resp.Request.URL, resp.StatusCode)
case err := <-c.Err:
fmt.Printf("Error received: %s\n", err)
}
}
}
这会输出:
Status received for https://www.google.com: 200
Status received for https://golang.org: 200
Status received for https://github.com/: 200
说明
该示例创建了一个框架,用于使用单个客户端以扇出异步方式处理请求。它尝试尽可能快地检索尽可能多的URL。 在许多情况下,你可能希望通过类似工作池的方式进一步限制此操作。在特定存储或检索接口时这些异步Go例程也是有借鉴意义的。
这里还使用case语句处理多个通道。我们无需担心处理锁定问题,因为我们非常清楚将收到多少响应。如果放弃某些响应处理,那么另一种选择就是超时。
最后编辑: kuteng 文档更新时间: 2021-01-03 15:03 作者:kuteng