Go Context: Cancelation and Propagation

import "context"!

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

Suppose you need to make a sandwich, so you arrange three people to buy tomatoes, bread, and ham. The ham buyer found that there was no ham when he arrived at the supermarket, so he asked the clerk in the supermarket to make a ham for him on the spot. People who buy bread and tomatoes are on their way to the bakery and tomato shop respectively.
At this time, you suddenly decide not to eat ham. In order not to waste resources, we need a mechanism that allows the ham maker to stop making ham, the person who goes to the supermarket immediately stops going to the supermarket, and the person waiting for the ham immediately stops waiting for the ham.

Custom function 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())
	}
}

Cancel-

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")
}

By go run *.gorunning the above code, if not Stdin, then after 5 seconds output Hello. If there is within 5 seconds Stdin, it cancelwill run immediately 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()

Use channels and options

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)
} 

Channels and selection cannot handle complex thread trees.
Is the context okay?

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)

}

Example of multiple threads-

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)
			}
		}
	}
}

Guess you like

Origin blog.csdn.net/Hita999/article/details/112768767