IT评测·应用市场-qidao123.com技术社区

标题: 【GO】Context [打印本页]

作者: 自由的羽毛    时间: 2025-1-26 10:40
标题: 【GO】Context
context包的核心目标是为了资助开发者编写更加高效、可靠和可维护的并发程序。它提供了一套工具来处理请求范围的数据传递、超时、取消信号和goroutine生命周期管理等问题,这些都是当代分布式系统开发中的关键挑衅。通过合理使用context,可以显著改善应用程序的举动,并确保其在面临复杂的工作负载时仍然保持良好的性能和稳定性。
  1. context.Context 接口

context.Context 是一个接口,界说了四个方法:
Deadline() (deadline time.Time, ok bool):返回上下文截止时间(如果有的话)。如果没有设置,则ok为false。
Done() <-chan struct{}:返回一个通道,当该上下文被取消或超时时会关闭这个通道。可以监听这个通道来相识何时应该停止工作。
Err() error:在Done()通道关闭后调用,以获取导致上下文竣事的原因(如上下文被取消或超时)。
Value(key interface{}) interface{}:用于从上下文中检索键值对中的值。只有当你需要传递请求特定的数据时才使用它。
2. 创建Context

context.Background() 和 context.TODO() 都是创建一个新的空上下文的方法,但它们有不同用途:
Background() 主要用于主函数、初始化和测试代码中,作为所有其他上下文的根。
TODO() 用来表现开发者还没有决定怎样处理上下文,通常不应该出现在生产代码中。
3. 派生新Context

派生新的Context意味着基于现有的Context创建一个新的子Context。这答应你添加额外的信息到现有Context上,比如超时或取消信号。以下是几个告急的函数:
WithCancel(parent Context): 返回一个新的Context和一个取消函数。当调用取消函数时,新的Context会被取消,而且任多么待Done()通道的操作都会立刻收到通知。
WithDeadline(parent Context, deadline time.Time): 类似于WithCancel,但它会在指定的时间点自动取消新的Context。
WithTimeout(parent Context, timeout time.Duration): 设置一个相对的时间限期,在这段时间之后自动取消新的Context。
WithValue(parent Context, key, val interface{}): 答应你在Context中存储键值对。注意,为了类型安全,通常会界说一个特定类型的key类型(例如,自界说的布局体类型),而且只将它与特定的Context一起使用。
4. 取消Context

当你不再需要一个Context或者它的衍生Context时,你应该尽快调用取消函数。如许做有助于及时释放资源,并确保你的程序不会浪费计算本领在已经不需要的任务上。
5. 使用Context

在一个长时间运行的操作中,你可以定期查抄ctx.Done()是否关闭,以此来决定是否应该提前退出操作。如果你正在接收数据,那么在接收之前查抄ctx.Err()是否为非nil可以资助你避免不必要的工作。
6. Context不是为了传递业务数据

尽管WithValue方法答应你向Context添加值,但这不应该成为传递业务逻辑数据的主要方式。Context应该只包含少量的元数据,如请求ID、认证信息等,而不应该包含复杂的业务状态。
7. Context不应该被存储在布局体中

由于Context是计划为随着函数调用链向下传递的,因此不应该将其保存为布局体的字段。如许做的原因是为了避免潜在的生命周期问题以及使代码更加清楚和易于理解。
8. 避免使用全局变量保存Context

使用全局变量保存Context会导致程序难以理解和维护,因为这使得跟踪Context的泉源和使用变得困难。相反,应当通过参数列表显式地传递Context。

9.场景使用

创建根本Context

   context.Background()

  1. ctx := context.Background()
复制代码

   context.TODO()

  1. ctx := context.TODO()
复制代码

派生新Context

派生新的Context意味着创建一个子Context,它继承了父Context的举动,并可以添加额外的功能,比如超时或携带值。
   context.WithCancel

  1. ctx, cancel := context.WithCancel(context.Background())
  2. defer cancel() // 确保调用cancel以释放资源
复制代码

   context.WithDeadline

  1. deadline := time.Now().Add(5 * time.Second)
  2. ctx, cancel := context.WithDeadline(context.Background(), deadline)
  3. defer cancel()
复制代码

   context.WithTimeout

  1. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
  2. defer cancel()
复制代码

   context.WithValue

  1. type key string
  2. ctx := context.WithValue(context.Background(), key("user_id"), "12345")
复制代码

监听Context的变化

当你的goroutine实行长时间运行的任务时,你可以监听ctx.Done()来查抄是否应该提前退出任务。
  1. select {
  2. case <-time.After(10 * time.Second):
  3.     fmt.Println("Operation completed.")
  4. case <-ctx.Done():
  5.     fmt.Println("Operation was canceled:", ctx.Err())
  6. }
复制代码
这里我们使用select语句来等候两个条件之一:要么操作完成,要么Context被取消。如果Context被取消,则打印出取消的原因。
在网络服务中使用Context

在网络服务器中,context常用于控制HTTP请求的生命周期。例如,在标准库的net/http包中,每个请求都会有一个关联的context.Context对象,可以通过http.Request.Context()方法获取。
  1. func handler(w http.ResponseWriter, r *http.Request) {
  2.     ctx := r.Context()
  3.     select {
  4.     case <-time.After(5 * time.Second):
  5.         fmt.Fprintf(w, "Hello!")
  6.     case <-ctx.Done():
  7.         http.Error(w, ctx.Err().Error(), http.StatusInternalServerError)
  8.     }
  9. }
复制代码
在这个例子中,如果请求被客户端取消或超时,ctx.Done()会被关闭,导致服务器停止处理请求并向客户端发送错误响应。
Context与数据库或其他长期运行的操作

当你实行可能需要很长时间才能完成的操作(如数据库查询),你应该始终监听传入的Context信号,以便在必要时停止操作。
  1. db, err := sql.Open("mysql", "...")
  2. if err != nil {
  3.     log.Fatal(err)
  4. }
  5. // 使用带超时的Context
  6. ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
  7. defer cancel()
  8. var name string
  9. err = db.QueryRowContext(ctx, "SELECT name FROM users WHERE id=?", 1).Scan(&name)
  10. if err != nil {
  11.     if errors.Is(err, context.DeadlineExceeded) {
  12.         log.Println("Query timed out")
  13.     } else {
  14.         log.Println("Query failed:", err)
  15.     }
  16. } else {
  17.     fmt.Println("User name:", name)
  18. }
复制代码
以上展示了怎样使用context与数据库交互,并设置了一个3秒的超时。如果查询未能在此时间内完成,操作将被取消。

   综上所述,context包提供了一套机制,资助你管理goroutine之间共享的数据,控制并发操作的生命周期,并优雅地处理超时和取消情况。精确使用context对于编写高效、可靠的服务端应用程序非常告急。
  

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/) Powered by Discuz! X3.4