上下文(context)的使用·协程控制

package main

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

func main() {
   // 使用context.Background()创建一个空上下文
   ctx, cancel := context.WithCancel(context.Background())

   // 启动协程1
   go func(ctx context.Context) {
      counter := 0 // 设置一个计数器,用于确保任务只执行一次
      for {
         select {
         case <-ctx.Done(): // 收到上下文的cancel信号
            fmt.Println("协程1收到上下文的cancel信号,即将停止任务")
            return
         default:
            if counter == 0 {
               counter = 1
               fmt.Println("协程1开始执行任务……")
            }
         }
      }
   }(ctx)

   // 启动协程2
   go func(ctx context.Context) {
      counter := 0 // 设置一个计数器,用于确保任务只执行一次
      for {
         select {
         case <-ctx.Done(): // 收到上下文的cancel信号
            fmt.Println("协程2收到上下文的cancel信号,即将停止任务")
            return
         default:
            if counter == 0 {
               counter = 1
               fmt.Println("协程2开始执行任务……")
            }
         }
      }
   }(ctx)

   // 等待3秒后取消上下文
   time.Sleep(time.Second * 3)
   cancel()

   // 再次等待3秒让两个协程有时间执行
   time.Sleep(time.Second * 3)

   fmt.Println("main()执行完毕")
}

// ========== 输出过程·开始 ========== //
// 协程2开始执行任务……
// 协程1开始执行任务……
// 协程1收到上下文的cancel信号,即将停止任务
// 协程2收到上下文的cancel信号,即将停止任务
// main()执行完毕
// ========== 输出过程·结束 ========== //
// 说明:由于任务调度的关系,两个协程哪个先执行是无法确定的,同理哪个先停止也是无法确定的。

// ========== 总结 ========== //
// 1、上下文可以用于协程嵌套,即可以控制子协程和孙子协程,最典型的使用场景是当父协程由于某种原因需要停止时,
//    还要通知其下子协程和孙子协程也停止执行,这时就可以通过上下文发出cancel信号来通知。

Copyright © 2024 码农人生. All Rights Reserved