1.值传递


值传递只是context的一个辅助功能,并不是核心功能。一般我们只用context来传递不影响业务主逻辑的可选数据,比如日志信息、调试信息以及元信息等等。


package main

import (
	"context"
	"fmt"
)

func readContext(ctx context.Context) {
	traceId, ok := ctx.Value("key").(string)
	if ok {
		fmt.Println("readContext key=", traceId)i
	} else {
		fmt.Println("readContext no key")
	}
}

func main() {
	ctx := context.Background()
	readContext(ctx)
	ctx = context.WithValue(ctx, "key", "beautiful")
	readContext(ctx)
}

在使用WithValue对ctx包装时,可以设置一个key-value键值对,在goroutine之间传递。


2.超时控制


http请求设置超时时间

package main

import (
	"context"
	"fmt"
	"time"
)

func httpRequest(ctx context.Context) {
	for {
		// 处理http请求
		select {
		case <- ctx.Done():
			fmt.Println("Request timed out")
			return
		case <- time.After(time.Second):
			fmt.Println("Loading...")
		}
	}
}

func main() {
	fmt.Println("start TestTimeoutContext")
	ctx, cancel := context.WithTimeout(context.Background(), time.Second * 3)
	defer cancel()
	httpRequest(ctx)
	time.Sleep(time.Second * 5)
}

//start TestTimeoutContext
//Loading...
//Loading...
//Request timed out


文件io或者网络io等耗时操作,可以查看剩余的时间是否充足,决定是否进行下一步操作

package main

import (
	"context"
	"fmt"
	"time"
)

func copyFile(ctx context.Context)  {
	deadline, ok := ctx.Deadline()
	if ok == false {
		return
	}
	// deadline.Sub(time.Now()) 截止时间与当前时间的差值
	isEnough := deadline.Sub(time.Now()) > time.Second * 5
	if isEnough {
		fmt.Println("copy file")
	} else {
		fmt.Println("isEnough is false return")
		return
	}
}

func main() {
	ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second * 4))
	defer cancel()
	copyFile(ctx)
	time.Sleep(time.Second * 5)
}


//isEnough is false return


3.取消控制


goroutine发送取消信号,保证自己这个逻辑中发散出去的goroutine全部成功取消

package main

import (
	"context"
	"fmt"
	"time"
)

func gen(ctx context.Context) <-chan int {
	ch := make(chan int)
	go func() {
		var n int
		for {
			select {
			case ch <- n:
				n++
				time.Sleep(time.Second)
			case <-ctx.Done():
				return
			}
		}
	}()
	return ch
}

func main() {
	// 创建一个Cancel context
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	for n := range gen(ctx) {
		fmt.Println(n)
		if n == 5 {
			// 达到要求之后触发cancel
			cancel()
			break
		}
	}
}
//0
//1
//2
//3
//4
//5


参考资料: