简析go语言并发模式(4)
超时和取消模式:超时模式在超时返回后,已经创建的goroutine可能依然处于等待状态,没有返回,也没有被回收,依然占用资源。这种情况下一般使用Go的context包来实现取消模式。Go在1.17标准库中引入context包。
import ( "context" "errors" "io" "log" "net/http" "net/http/httptest" "time" ) type result struct { value string } func requestData(servers ...*httptest.Server) (result, error) { c := make(chan result, len(servers)) // http包支持利用context.Context的超时和取消机制 // 利用context.WithCancel创建一个可以取消的context.Context变量ctx ctx, cancel := context.WithCancel(context.Background()) // 函数返回前取消request请求 defer cancel() queryFunc := func(i int, server *httptest.Server) { url := server.URL req, err := http.NewRequest("GET", url, nil) if err != nil { log.Printf("query goroutine-%d: http NewRequest error: %s", i, err) return } // 使用context.Context变量ctx req = req.WithContext(ctx) log.Printf("query goroutine-%d: send request...\n", i) resp, err := http.DefaultClient.Do(req) if err != nil { log.Printf("query goroutine-%d: get return error: %s\n", i, err) return } log.Printf("query goroutine-%d: get response\n", i) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) c <- result{ value: string(body), } return } for i, serv := range servers { go queryFunc(i, serv) } select { case r := <-c: return r, nil case <-time.After(500 * time.Microsecond): return result{}, errors.New("timeout") } } func fakeServer(name string, interval int) *httptest.Server { // 使用httptest包NewServer函数创建虚拟server return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Printf("%s receive a http request\n", name) time.Sleep(time.Duration(interval) * time.Microsecond) w.Write([]byte(name + " :ok")) })) } func main() { res, err := requestData( fakeServer("server-1", 200), fakeServer("server-2", 1000), fakeServer("server-3", 600), ) if err != nil { log.Printf("invoke requestData error: %s", err) return } log.Println(res) time.Sleep(10 * time.Second) } $ go run go-concurrency-pattern.go 2023/05/08 23:28:36 query goroutine-2: send request... 2023/05/08 23:28:36 query goroutine-1: send request... 2023/05/08 23:28:36 query goroutine-0: send request... 2023/05/08 23:28:36 invoke requestData error: timeout
Go语言基础及实战 文章被收录于专栏
Go语言学习笔记、语法知识、技术要点和个人理解及实战