zoukankan      html  css  js  c++  java
  • golang context学习记录1

    1.前言

    一个请求,可能涉及多个API调用,多个goroutine,如何在多个API 之间,以及多个goroutine之间协作和传递信息,就是一个问题。

    比如一个网络请求Request,需要开启一些goroutine去访问后端资源(比如,数据库,RPC服务等),这些goroutine又可能会开启其他的goroutine,如何跟踪和控制这些goroutine呢?

    golang定义了 context包,用于解决这个问题。

    context可以在多个API和进程之间,实现deadlines截止日期操作、cancelation signals取消操作以及传递request-scoped的值(即传递参数)。

    context一个最大的特点是可以继承。父context,可以派生子context,子context有又可以派生子context。如果父context被取消,子context及其子context都会被取消。

    常用派生的方法有:WithCancel WithDeadline WithTimeout WithValue.
    其中,

    • WithCancel用于主动取消自身以及子context。
    • WithDeadlineWithTimeout用于超时情况下的取消自身以及子context。WithTimeout实现上直接调用WithDeadline
    • WithValue用于context传递request-scoped的参数,而不是向函数传递的可选参数。

    2.例子

    下面例子演示如何控制多个goroutine的退出。

    首先,启动3个goroutine,分别命名为"1"、"2"、"3",每个goroutine又启动一个goroutine。也就是有6个goroutine。它们之间的关系如下:

    • 1
      • 11
    • 2
      • 21
    • 3
      • 31

    最后,在main中调用取消操作cancel,先是1,2,3收到信号退出,1,2,3退出的时候又调用它们的cancel,这样所有的goroutine都被取消并退出。

    具体代码如下:

    package main
    
    import (
            "context"
            "fmt"
            "time"
    )
    
    
    func PrintTask(ctx context.Context, taskName string) {
    
            for {
    
                    select {
    
                    case <- ctx.Done():
                            fmt.Println("task:", taskName, " exit...")
                            return
                    default:
                            time.Sleep(1*time.Second)
                            fmt.Println("task:", taskName, " doing something...")
                    }
    
            }
    
    }
    
    func mainTask(ctx context.Context, taskName string) {
    
            ctx1, cancel := context.WithCancel(ctx)
            defer cancel()
    
            // create a new task
            newTaskName := taskName + "1"
            go PrintTask(ctx1, newTaskName)
    
    
            for {
    
                    select {
    
                    case <- ctx.Done():
                            fmt.Println("task:", taskName, " exit...")
                            return
                    default:
                            time.Sleep(1*time.Second)
                            fmt.Println("task:", taskName, " doing something...")
                    }
    
            }
    
    
    }
    
    func main() {
    
            ctx := context.Background()
            ctx, cancel := context.WithCancel(ctx)
    
            go mainTask(ctx, "1")
            go mainTask(ctx, "2")
            go mainTask(ctx, "3")
    
            time.Sleep(3*time.Second)
            cancel()
            fmt.Println("main exit...")
            time.Sleep(3*time.Second)
    }
    

    输出

    task: 1  doing something...
    task: 21  doing something...
    task: 11  doing something...
    task: 3  doing something...
    task: 2  doing something...
    task: 31  doing something...
    task: 3  doing something...
    task: 2  doing something...
    task: 11  doing something...
    task: 21  doing something...
    task: 31  doing something...
    task: 1  doing something...
    task: 11  doing something...
    task: 3  doing something...
    task: 1  doing something...
    task: 21  doing something...
    task: 2  doing something...
    task: 31  doing something...
    main exit...
    task: 11  doing something...
    task: 11  exit...
    task: 21  doing something...
    task: 21  exit...
    task: 3  doing something...
    task: 3  exit...
    task: 31  doing something...
    task: 31  exit...
    task: 1  doing something...
    task: 1  exit...
    task: 2  doing something...
    task: 2  exit...
    

    更多参考

    Golang并发控制--context的使用

    Golang Context深入理解

  • 相关阅读:
    防删没什么意思啊,直接写废你~
    绝大多数情况下,没有解决不了的问题,只有因为平时缺少练习而惧怕问题的复杂度,畏惧的心理让我们选择避让,采取并不那么好的方案去解决问题
    Java 模拟面试题
    Crossthread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on
    一步步从数据库备份恢复SharePoint Portal Server 2003
    【转】理解 JavaScript 闭包
    Just For Fun
    The database schema is too old to perform this operation in this SharePoint cluster. Please upgrade the database and...
    Hello World!
    使用filter筛选刚体碰撞
  • 原文地址:https://www.cnblogs.com/lanyangsh/p/10890241.html
Copyright © 2011-2022 走看看