简析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语言学习笔记、语法知识、技术要点和个人理解及实战

全部评论

相关推荐

重生2012之我是java程序员:换个稍微正式点的照片吧
点赞 评论 收藏
分享
牛客618272644号:佬携程工作怎么样,强度大吗
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务