golang Context for goroutines

Overview

golang of channel mechanisms are based on concurrent mode CSP (Communicating Sequencial Processes) model.

By Channel, you can easily write a plurality coroutine collaboration (goroutines) code, the code sequence into parallel code is very simple. After transformation into parallel codes, though can make better use of hardware multi-core effectively improve the efficiency of the code, but also poses a problem code control.

Parallel execution of the code is clearly than the code sequence harder to manage and control, then, we must rely on golang Context interface provided to help us control the goroutine.

goroutine control

Goroutine between the basic control is by the interactive channel data:

 1  func routineSample() {
 2    ch := make(chan int, 10)
 3    go p1(ch)
 4    go c1(ch)
 5    go c2(ch)
 6  
 7    time.Sleep(10 * time.Second)
 8  }
 9  
10  func p1(ch chan int) {
11    fmt.Println("Parent go routine!")
12  
13    for i := 0; i < 10; i++ {
14      ch <- i
15    }
16  
17    close(ch)
18  }
19  
20  func c1(ch chan int) {
21    fmt.Println("Child 1 go routine!")
22    for c := range ch {
23      fmt.Printf("child 1, recivie: %d\n", c)
24      time.Sleep(100 * time.Millisecond)
25    }
26  }
27  
28  func c2(ch chan int) {
29    fmt.Println("Child 2 go routine!")
30    for c := range ch {
31      fmt.Printf("child 2, recivie: %d\n", c)
32      time.Sleep(100 * time.Millisecond)
33    }
34  }

The above is an example of the most basic, p1 functions continues to send to the channel, c1 and c2, is responsible for processing the data. Although achieved through channel c1, c2 concurrent very simple, but it can be seen, p1 To control the c1, c2 not so easy .

In this case, it is necessary to control concurrent Context interface by coroutine.

Cancel control

Cancellation control task refers to an initiator, under certain conditions, the transmission signal has been received indicating task coroutine stopping mission.

 1  func routineSample() {
 2   ch := make(chan int, 10)
 3   ctx, cancel := context.WithCancel(context.Background())
 4   go p1(ctx, ch)
 5   go c1(ctx, ch)
 6   go c2(ctx, ch)
 7  
 8   // 300 ms之后取消任务
 9   time.Sleep(300 * time.Millisecond)
10   cancel()
11  
12   time.Sleep(10 * time.Second)
13  }
14  
15  func p1(ctx context.Context, ch chan int) {
16   fmt.Println("Parent go routine!")
17  
18   for i := 0; i < 10; i++ {
19     ch <- i
20   }
21  
22   close(ch)
23  }
24  
25  func c1(ctx context.Context, ch chan int) {
26   fmt.Println("Child 1 go routine!")
27   for c := range ch {
28     select {
29     case <-ctx.Done():
30       fmt.Println("child 1, return!")
31       return
32     default:
33       fmt.Printf("child 1, recivie: %d\n", c)
34     }
35     time.Sleep(100 * time.Millisecond)
36   }
37  }
38  
39  func c2(ctx context.Context, ch chan int) {
40   fmt.Println("Child 2 go routine!")
41   for c := range ch {
42     select {
43     case <-ctx.Done():
44       fmt.Println("child 2, return!")
45       return
46     default:
47       fmt.Printf("child 2, recivie: %d\n", c)
48     }
49     time.Sleep(100 * time.Millisecond)
50   }
51  }

After 300 ms, the transmission signal cancellation task Cancel () , C1 and c2 select by determining whether a cancellation signal after the received signal is canceled, the processing exits.

As it can be seen by the results of c1 and c2 stops the exit after about 5-6 processing tasks.

Timeout control

In addition to deregulation, context as well timeout control.

 1  func routineSample() {
 2   ch := make(chan int, 10)
 3   ctx, _ := context.WithTimeout(context.Background(), 300*time.Millisecond)
 4   go p1(ctx, ch)
 5   go c1(ctx, ch)
 6   go c2(ctx, ch)
 7  
 8   time.Sleep(10 * time.Second)
 9  }
10  
11  func p1(ctx context.Context, ch chan int) {
12   fmt.Println("Parent go routine!")
13  
14   for i := 0; i < 10; i++ {
15     ch <- i
16   }
17  
18   close(ch)
19  }
20  
21  func c1(ctx context.Context, ch chan int) {
22   fmt.Println("Child 1 go routine!")
23   for c := range ch {
24     select {
25     case <-ctx.Done():
26       fmt.Println("child 1, return!")
27       return
28     default:
29       fmt.Printf("child 1, recivie: %d\n", c)
30     }
31     time.Sleep(100 * time.Millisecond)
32   }
33  }
34  
35  func c2(ctx context.Context, ch chan int) {
36   fmt.Println("Child 2 go routine!")
37   for c := range ch {
38     select {
39     case <-ctx.Done():
40       fmt.Println("child 2, return!")
41       return
42     default:
43       fmt.Printf("child 2, recivie: %d\n", c)
44     }
45     time.Sleep(100 * time.Millisecond)
46   }
47  }

Timeout control WithTimeout also returns a cancel function, perform the task can be canceled before reaching the time-out, waiting for the example above tasks automatically canceled when the timeout is reached without the use cancel function.

Between the traditional values ​​goroutine

Generally, the service data are transmitted between goroutine through Channel, in addition, also some of the metadata may be delivered via goroutine control channel.

 1  func routineSample() {
 2   ch := make(chan int, 10)
 3   // 哪个goroutine收到5号任务, 就退出, 不再做后续的任务
 4   ctx := context.WithValue(context.Background(), "finish", 5)
 5   go p1(ctx, ch)
 6   go c1(ctx, ch)
 7   go c2(ctx, ch)
 8  
 9   time.Sleep(10 * time.Second)
10  }
11  
12  func p1(ctx context.Context, ch chan int) {
13   fmt.Println("Parent go routine!")
14  
15   for i := 0; i < 10; i++ {
16     ch <- i
17   }
18  
19   close(ch)
20  }
21  
22  func c1(ctx context.Context, ch chan int) {
23   fmt.Println("Child 1 go routine!")
24   for c := range ch {
25     if c == ctx.Value("finish").(int) {
26       fmt.Println("child 1, return!")
27       return
28     }
29     fmt.Printf("child 1, recivie: %d\n", c)
30     time.Sleep(100 * time.Millisecond)
31   }
32  }
33  
34  func c2(ctx context.Context, ch chan int) {
35   fmt.Println("Child 2 go routine!")
36   for c := range ch {
37     if c == ctx.Value("finish").(int) {
38       fmt.Println("child 2, return!")
39       return
40     }
41     fmt.Printf("child 2, recivie: %d\n", c)
42     time.Sleep(100 * time.Millisecond)
43   }
44  }

The above example is to place a key = "finish" in the context of the task number, or if the job number c1 and c2 are received which is the same, the task will not be executed. It can be seen by the above example operation, performed c1 or c2 No. 5 to the task when it will exit coroutines. but who received the 5th mission is uncertain, execute it several times above code can be found sometimes quit c1, c2 sometimes quit.

to sum up

context is controlling the context of concurrent coroutine, using context, can be simplified large timeout control coroutine code removes coroutine execution, as well as traditional values ​​of between coroutine. context is very convenient, but not indiscriminately, transmitted through the channel service data, do not put in context to pass.

In addition, context is thread-safe, you can rest assured that the use of multiple co-process.

Guess you like

Origin www.cnblogs.com/wang_yb/p/12234475.html