• golang:context


    context作用

    goroutine的退出机制

    多个goroutine都是平行的被调度的,多个goroutine如何协调工作涉及通信、同步、通知和退出

    • 通信:goroutine之间的通信同步chan通道

    • 同步:不带缓冲的chan提供了一个天然的同步等待机制。通过WaitGroup也可以为多个goroutine提供同步等待机制

    • 通知:这个通知和上面通信的数据不一样,通知通常不是业务数据,而是管理、控制流数据。要处理这个也好办,在输入端绑定两个chan,一个用于业务流数据,另一个用于异常通知数据,然后通过 select 收敛进行处理。这个方案可以解决简的问题,但不是一个通用的解决方案。

    • 退出:goroutine 之间没有父子关系,如何通知 goroutine 退出?可以通过增加一个个单独的通道,借助通道和 select 的广播机制( close channel to broadcast)实现退出

    通知退出机制:

    • 读取已经关闭的通道不会引起阻塞,也不会导致panic,而是立即返回该通道存储类型的零值

    • 关闭select监听的某个通道能使select立即感知这种通知,然后进行相应的处理,即所谓的退出通知机制

    contet库的设计目的就是跟踪 goroutine调用树,并在这些goroutine 调用树中递通知和元数据

    • 退出通知机制:通知可以传递给整个 goroutine调用树上的每一个goroutine

    • 传递数据:数据可传递给整个goroutine 调用树上的每一个goroutine

    使用

    1. var wg sync.WaitGroup
    2. func main() {
    3. background := context.Background()
    4. //通过cancel进行控制
    5. /*cancelctx, cancelFunc := context.WithCancel(background)
    6. wg.Add(2)
    7. go jiankong1(cancelctx)
    8. time.Sleep(time.Second * 2)
    9. println("并不是因为主协程退出,而导致另一个协程退出,而是通过cancel方法通知另一个协程进行退出!")
    10. cancelFunc()
    11. wg.Wait()
    12. println("完成退出")*/
    13. //通过deadline进行控制,也可以通过返回的cancelFunc手动进行控制
    14. /*deadline, _ := context.WithDeadline(background, time.Now().Add(time.Second*2))
    15. go deadF(deadline)
    16. time.Sleep(time.Second * 4)
    17. println("结束")*/
    18. //通过timeout控制,也可以通过返回的cancelFunc手动进行控制 超时以后报的错和deadline控制方式一样 context deadline exceeded
    19. timeout, _ := context.WithTimeout(background, time.Second*2)
    20. go deadF(timeout)
    21. time.Sleep(time.Second * 4)
    22. println("结束")
    23. }
    24. func deadF(ctx context.Context) {
    25. for true {
    26. select {
    27. case <-ctx.Done():
    28. fmt.Println("只给了两秒的执行时间,时间到了,我得退出了。")
    29. //此处打印的错误为 context deadline exceeded
    30. println(ctx.Err().Error())
    31. return
    32. default:
    33. time.Sleep(time.Millisecond * 1000)
    34. fmt.Println("我正在执行...")
    35. }
    36. }
    37. }
    38. func jiankong1(ctx context.Context) {
    39. defer wg.Done()
    40. cancel, _ := context.WithCancel(ctx)
    41. go jiankong2(cancel)
    42. for true {
    43. select {
    44. case <-ctx.Done():
    45. fmt.Println("别人通知我主动退出了。在此处进行收尾工作,释放资源等")
    46. //此处报错为:context canceled
    47. fmt.Println(ctx.Err().Error())
    48. return
    49. default:
    50. time.Sleep(time.Millisecond * 100)
    51. fmt.Println("我在持续监控中...")
    52. }
    53. }
    54. }
    55. func jiankong2(ctx context.Context) {
    56. defer wg.Done()
    57. for true {
    58. select {
    59. case <-ctx.Done():
    60. fmt.Println("上级通知我主动退出了。")
    61. fmt.Println(ctx.Err().Error())
    62. return
    63. default:
    64. time.Sleep(time.Millisecond * 100)
    65. fmt.Println("me在持续监控中...")
    66. }
    67. }
    68. }

    Tips:

    异步任务使用context注意点:

    使用go func进行异步任务传入context时,要考虑context的过期时间,如果异步任务不考虑过期时间,则最好传入一个无过期时间的context,负责异步任务多或执行时间长context会过期,影响异步任务的执行。

    场景:mongo批量插入数据后,将返回的Id集合传入异步任务(在异步任务中通过id查询数据),如果共用了接口设置过期时间的context,可能会导致一部分数据查询不到(context过期导致)

  • 相关阅读:
    HTML学生中秋节日网页设计模板 DIV布局大学生中秋节网页作业制作 八月十五中秋静态网页成品代码下载 中秋节日网页设计作品
    接口测试框架:Http+Requests(1)
    基于 Sobol 序列和纵横交叉策略的麻雀搜索算法-附代码
    快速幂
    C++学习 --map
    P8198 [传智杯 #4 决赛] 背单词的小智 二分答案+前缀和
    信创产业快速发展,开发者应该了解什么?
    Java实现图书管理系统
    centos7操作系统 ---ansible剧本离线快速部署etcd集群
    YB1205B 外置MOS异步升压恒流LED驱动控制器
  • 原文地址:https://blog.csdn.net/q79030/article/details/132975671