## 并发操作客户端请求 在Go中,并行执行客户端请求相对简单。 在下面示例中,我们将使用客户端使用Go缓冲通道执行多个URL请求。 响应和错误都将转到一个单独的通道,任何有权访问客户端的人都可以轻松访问。 在本节中,创建客户端,读取通道以及处理响应和错误都将在main.go文件中完成。 ### 实践 1. 建立 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 } ``` 2. 建立 exec.go: ``` package async // FetchAll 遍历请求所有的url func FetchAll(urls []string, c *Client) { for _, url := range urls { go c.AsyncGet(url) } } ``` 3. 建立 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) } } } ``` 4. 这会输出: ``` 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语句处理多个通道。我们无需担心处理锁定问题,因为我们非常清楚将收到多少响应。如果放弃某些响应处理,那么另一种选择就是超时。 * * * * 学识浅薄,错误在所难免。欢迎在群中就本书提出修改意见,以飨后来者,长风拜谢。 Golang中国(211938256) beego实战(258969317) Go实践(386056972)