0
点赞
收藏
分享

微信扫一扫

Go Context - Cancelation and Propagation

清冷的蓝天天 2022-01-06 阅读 61
golang

import "context"!

view context package source code!
see example code for a server that uses contexts!
view golang documentation about context!

自定义一个函数sleepAndTalk() -

func sleepAndTalk(ctx context.Context, d time.Duration, msg string) {
	select {
	case <- time.After(d)
		fmt.Println(msg)
	case <- ctx.Done()
		log.Print(ctx.Err())
	}
}

取消 -

func main() {
	ctx := Context.Background()
	ctx, cancel := context.WithCancel(ctx)
	go func () {
		s := bufio.NewScanner(os.Stdin)
		s.Scan()
		cancel()
	}()
	sleepAndTalk(ctx, 5 * time.Second, "Hello")
}

go run *.go运行上面的代码,如果没有Stdin,则5秒后输出Hello。如果在5秒内有Stdin,则可以立即cancel将会运行的sleepAndTalk()

func main() {
	ctx := Context.Background()
	ctx, cancel := context.WithCancel(ctx)
	go func () {
		time.Sleep(time.Second)
		cancel()
	}()
	sleepAndTalk(ctx, 5 * time.Second, "Hello")
}

Cancel() after 1 second. The code above is equivalent to -

func main() {
	ctx := Context.Background()
	ctx, cancel := context.WithCancel(ctx)
	time.AfterFunc(time.Second, cancel)
	sleepAndTalk(ctx, 5 * time.Second, "Hello")
}

or -

func main() {
	ctx := Context.Background()
	ctx, cancel := context.WithTimeout(ctx, time.Second)
	cancel() // release resources for timer
	sleepAndTalk(ctx, 5 * time.Second, "Hello")
}

Methods that handle cancelations -

Background()
WithCancel()
WithTimeout()
WithDeadline()

使用通道和选择

func main() {
	stop := make(chan bool)
	go func() {
		for {
			select {
			case <- stop: // 在channel收到值后输出stop并返回
				fmt.Println("stop!")	
				return
			default: // 在channel收到任何bool之前一直会跑default
				fmt.Println("running...")
				time.Sleep(1 * time.Second)
			}
		}
	}()
	
	time.Sleep(5 * time.Second)
	fmt.Println("sending value to channel \"stop\"")
	stop <- true
	time.Sleep(5 * time.Second)
} 

通道和选择无法处理复杂的线程树。
上下文可以吗?

func main() {
	// Background() is the root Context
	// WithCancel() add a new Context node
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		for {
			select {
			case <- ctx.Done(): // Done()在引用cancel()之后打开channel
				fmt.Println("stop!")	
				return
			default: // 在channel收到任何bool之前一直会跑default
				fmt.Println("running...")
				time.Sleep(1 * time.Second)
			}
		}
	}()

	time.Sleep(5 * time.Second)
	fmt.Println("sending value to channel \"stop\"")
	cancel()
	time.Sleep(5 * time.Second)

}

多个线程的例子 -

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	go worker(ctx, node1)
	go worker(ctx, node2)
	go worker(ctx, node3)
	time.Sleep(5 * time.Second)
	fmt.Println("sending value to channel \"stop\"")
	cancel()
	time.Sleep(5 * time.Second)
}

func worker(ctx context.Context, name string) {
	go func() {
		for {
			select {
			case <- ctx.Done(): // Done()在引用cancel()之后打开channel
				fmt.Println(name, "stop!")	
				return
			default: // 在channel收到任何bool之前一直会跑default
				fmt.Println(name, "running...")
				time.Sleep(1 * time.Second)
			}
		}
	}
}

举报

相关推荐

0 条评论