go context 四种衍生用法

123 阅读1分钟

本文已参加「新人创作礼」活动,一起开启掘金创作之路。

go context 四种衍生用法

我在这就不具体的讲解他的用法\含义\以及低层原理,大家可以百度搜索学习,我在这直接上代码,简单实例

WithCancel


func main() {
	//根context
	background := context.Background()
	ctx, cancel := context.WithCancel(background)
	go watch(ctx, "【监控1】")
	go watch(ctx, "【监控2】")
	go watch(ctx, "【监控3】")
	time.Sleep(5 * time.Second)
	fmt.Println("可以了,通知监控停止")
	cancel()
	//为了检测监控过是否停止,如果没有监控输出,就表示停止了
	time.Sleep(5 * time.Second)
}
func watch(ctx context.Context, name string) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println(name, "监控退出,停止了...")
			return
		default:
			fmt.Println(name ,"goroutine监控中...")
			time.Sleep(time.Second)
		}
	}
	/**
	例子中启动了3个监控goroutine进行不断的监控,每一个都使用Context进行跟踪,
	当我们使用cancel函数通知取消时候,这3个 goroutine都会被结束。
	所有基于这个context或者衍生出来的子Context都会收到通知,
	这样就可以进行清理操作最终释放goroutine了
	*/
}

WithDeadline


func main() {
	ctx := context.Background()
	t := time.Now().Add(5 * time.Second)
	//cc, cancelFunc := context.WithDeadline(ctx, t)
	cc, _ := context.WithDeadline(ctx, t)

	go watch(cc, "【监控1】")
	go watch(cc, "【监控2】")
	//cancelFunc()
	
	time.Sleep(6 * time.Second)

}
func watch(ctx context.Context, name string) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println(name, "超时或者主动退出,停止了...")
			return
		default:
			fmt.Println(name, "goroutine监控中...")
			time.Sleep(time.Second)
		}
	}
}

/**
这个方法,就有两种结束的方法,一种是time设定的时间到了,自动停止,
一种是,提前调用cancelFunc(),提前结束
*/

留一个探讨问题,如果用下面的方法,会不会打印 -- "超时退出,停止了""

func watch2(ctx context.Context, name string) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println(name, "超时或者主动退出,停止了...")
			return
		case <-time.After(2 * time.Second):
			fmt.Println(name, "超时退出,停止了...")
			return
		default:
			fmt.Println(name, "goroutine监控中...")
			time.Sleep(time.Second)
		}
	}
}

WithTimeout


func main() {

	background := context.Background()

	timeoutContext, _ := context.WithTimeout(background, 5*time.Second)

	go watch(timeoutContext,"[监控一]")
	go watch(timeoutContext,"[监控二]")

	fmt.Println("现在开始等待8秒,time=", time.Now().Unix())
	time.Sleep(8 * time.Second)

	//fmt.Println("等待8秒结束,准备调用cancel()函数,发现两个子协程已经结束了,time=", time.Now().Unix())
	//cancelFunc()


}

func watch(ctx context.Context, name string) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println(name, "监控退出,停止了...")
			return
		default:
			fmt.Println(name, "goroutine监控中...")
			time.Sleep(time.Second)
		}
	}
}

/**
这个和哪个WithDeadline 用法差不多,具体细节以及低层代码原理,就不在这解析了
*/

WithValue

/**
这个还是比较有意思的
key val 都是 interface
*/

func main() {
	background := context.Background()
	ctx1 := context.WithValue(background, "01", "hello")
	test2(ctx1)
}


func test1(ctx context.Context) context.Context{
	ctx02 := context.WithValue(ctx, "02", "world")
	return ctx02
}

func test2(ctx context.Context) {
	fmt.Println(ctx.Value("01"))
	fmt.Println(ctx.Value("02"))
}

/**
输出:
hello
<nil>
*/



func main() {
	background := context.Background()
	ctx1 := context.WithValue(background, "01", "hello")
	ctx2 := test1(ctx1)
	test2(ctx2)
}


func test1(ctx context.Context) context.Context{
	ctx02 := context.WithValue(ctx, "02", "world")
	return ctx02
}

func test2(ctx context.Context) {
	fmt.Println(ctx.Value("01"))
	fmt.Println(ctx.Value("02"))
}

/**
输出:
hello
world
*/