Go 语言 context 都能做什么?

这篇具有很好参考价值的文章主要介绍了Go 语言 context 都能做什么?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

原文链接: Go 语言 context 都能做什么?

很多 Go 项目的源码,在读的过程中会发现一个很常见的参数 ctx,而且基本都是作为函数的第一个参数。

为什么要这么写呢?这个参数到底有什么用呢?带着这样的疑问,我研究了这个参数背后的故事。

开局一张图:

核心是 Context 接口:

// A Context carries a deadline, cancelation signal, and request-scoped values
// across API boundaries. Its methods are safe for simultaneous use by multiple
// goroutines.
type Context interface {
    // Done returns a channel that is closed when this Context is canceled
    // or times out.
    Done() <-chan struct{}

    // Err indicates why this context was canceled, after the Done channel
    // is closed.
    Err() error

    // Deadline returns the time when this Context will be canceled, if any.
    Deadline() (deadline time.Time, ok bool)

    // Value returns the value associated with key or nil if none.
    Value(key interface{}) interface{}
}

包含四个方法:

  • Done():返回一个 channel,当 times out 或者调用 cancel 方法时。
  • Err():返回一个错误,表示取消 ctx 的原因。
  • Deadline():返回截止时间和一个 bool 值。
  • Value():返回 key 对应的值。

有四个结构体实现了这个接口,分别是:emptyCtx, cancelCtx, timerCtxvalueCtx

其中 emptyCtx 是空类型,暴露了两个方法:

func Background() Context
func TODO() Context

一般情况下,会使用 Background() 作为根 ctx,然后在其基础上再派生出子 ctx。要是不确定使用哪个 ctx,就使用 TODO()

另外三个也分别暴露了对应的方法:

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context

遵循规则

在使用 Context 时,要遵循以下四点规则:

  1. 不要将 Context 放入结构体,而是应该作为第一个参数传入,命名为 ctx
  2. 即使函数允许,也不要传入 nil 的 Context。如果不知道用哪种 Context,可以使用 context.TODO()
  3. 使用 Context 的 Value 相关方法只应该用于在程序和接口中传递和请求相关的元数据,不要用它来传递一些可选的参数。
  4. 相同的 Context 可以传递给不同的 goroutine;Context 是并发安全的。

WithCancel

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)

WithCancel 返回带有新 Done 通道的父级副本。当调用返回的 cancel 函数或关闭父上下文的 Done 通道时,返回的 ctxDone 通道将关闭。

取消此上下文会释放与其关联的资源,因此在此上下文中运行的操作完成后,代码应立即调用 cancel

举个例子:

这段代码演示了如何使用可取消上下文来防止 goroutine 泄漏。在函数结束时,由 gen 启动的 goroutine 将返回而不会泄漏。

package main

import (
    "context"
    "fmt"
)

func main() {
    // gen generates integers in a separate goroutine and
    // sends them to the returned channel.
    // The callers of gen need to cancel the context once
    // they are done consuming generated integers not to leak
    // the internal goroutine started by gen.
    gen := func(ctx context.Context) <-chan int {
        dst := make(chan int)
        n := 1
        go func() {
            for {
                select {
                case <-ctx.Done():
                    return // returning not to leak the goroutine
                case dst <- n:
                    n++
                }
            }
        }()
        return dst
    }

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel() // cancel when we are finished consuming integers

    for n := range gen(ctx) {
        fmt.Println(n)
        if n == 5 {
            break
        }
    }
}

输出:

1
2
3
4
5

WithDeadline

func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)

WithDeadline 返回父上下文的副本,并将截止日期调整为不晚于 d。如果父级的截止日期已经早于 d,则 WithDeadline(parent, d) 在语义上等同于 parent

当截止时间到期、调用返回的取消函数时或当父上下文的 Done 通道关闭时,返回的上下文的 Done 通道将关闭。

取消此上下文会释放与其关联的资源,因此在此上下文中运行的操作完成后,代码应立即调用取消。

举个例子:

这段代码传递具有截止时间的上下文,来告诉阻塞函数,它应该在到达截止时间时立刻退出。

package main

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

const shortDuration = 1 * time.Millisecond

func main() {
    d := time.Now().Add(shortDuration)
    ctx, cancel := context.WithDeadline(context.Background(), d)

    // Even though ctx will be expired, it is good practice to call its
    // cancellation function in any case. Failure to do so may keep the
    // context and its parent alive longer than necessary.
    defer cancel()

    select {
    case <-time.After(1 * time.Second):
        fmt.Println("overslept")
    case <-ctx.Done():
        fmt.Println(ctx.Err())
    }
}

输出:

context deadline exceeded

WithTimeout

func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)

WithTimeout 返回 WithDeadline(parent, time.Now().Add(timeout))

取消此上下文会释放与其关联的资源,因此在此上下文中运行的操作完成后,代码应立即调用取消。

举个例子:

这段代码传递带有超时的上下文,以告诉阻塞函数应在超时后退出。

package main

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

const shortDuration = 1 * time.Millisecond

func main() {
    // Pass a context with a timeout to tell a blocking function that it
    // should abandon its work after the timeout elapses.
    ctx, cancel := context.WithTimeout(context.Background(), shortDuration)
    defer cancel()

    select {
    case <-time.After(1 * time.Second):
        fmt.Println("overslept")
    case <-ctx.Done():
        fmt.Println(ctx.Err()) // prints "context deadline exceeded"
    }

}

输出:

context deadline exceeded

WithValue

func WithValue(parent Context, key, val any) Context

WithValue 返回父级的副本,其中与 key 关联的值为 val

其中键必须是可比较的,并且不应是字符串类型或任何其他内置类型,以避免使用上下文的包之间发生冲突。 WithValue 的用户应该定义自己的键类型。

为了避免分配给 interface{},上下文键通常具有具体的 struct{} 类型。或者,导出的上下文键变量的静态类型应该是指针或接口。

举个例子:

这段代码演示了如何将值传递到上下文以及如何检索它(如果存在)。

package main

import (
    "context"
    "fmt"
)

func main() {
    type favContextKey string

    f := func(ctx context.Context, k favContextKey) {
        if v := ctx.Value(k); v != nil {
            fmt.Println("found value:", v)
            return
        }
        fmt.Println("key not found:", k)
    }

    k := favContextKey("language")
    ctx := context.WithValue(context.Background(), k, "Go")

    f(ctx, k)
    f(ctx, favContextKey("color"))
}

输出:

found value: Go
key not found: color

本文的大部分内容,包括代码示例都是翻译自官方文档,代码都是经过验证可以执行的。如果有不是特别清晰的地方,可以直接去读官方文档。

以上就是本文的全部内容,如果觉得还不错的话欢迎点赞转发关注,感谢支持。


官方文档:

  • https://pkg.go.dev/context@go1.20.5

源码分析:

  • https://mritd.com/2021/06/27/golang-context-source-code/
  • https://www.qtmuniao.com/2020/07/12/go-context/
  • https://seekload.net/2021/11/28/go-context.html

推荐阅读:文章来源地址https://www.toymoban.com/news/detail-514071.html

  • Go 语言 map 如何顺序读取?
  • Go 语言 map 是并发安全的吗?
  • Go 语言切片是如何扩容的?
  • Go 语言数组和切片的区别
  • Go 语言 new 和 make 关键字的区别
  • 为什么 Go 不支持 []T 转换为 []interface
  • 为什么 Go 语言 struct 要使用 tags

到了这里,关于Go 语言 context 都能做什么?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【自制键盘01】CH9329代码两则,让任何单片机都能做键盘

    CH9329是一款由WCH(Nanjing QinHeng Electronics Co. Ltd.)生产的USB转串口芯片,可以方便地将USB接口转换为串口接口,它在键盘设计这块可以实现作为MCU和电脑设备的“中间人”,把串口信号转换为按键。 来自官网页面: 串口转HID键盘鼠标芯片 CH9329 - 南京沁恒微电子股份有限公司

    2024年02月09日
    浏览(29)
  • Go语言中sync.Map、sync.Pool和Context的用法

    目录 【sync.Map】 实现线程安全的 map 类型  使用 sync.Map 实现并发读写的map 【sync.Pool】 使用 带缓冲channel 实现对象池 使用 sync.Pool 创建临时对象池 【Context 上下文】 Context应用:实现带超时功能的远程调用 Context应用:监控指令  Context应用:取消关联任务 之前在 Go语言中ar

    2024年02月05日
    浏览(36)
  • 【原文链接】Tri-Perspective View for Vision-Based 3D Semantic Occupancy Prediction

    原文链接:https://openaccess.thecvf.com/content/CVPR2023/papers/Huang_Tri-Perspective_View_for_Vision-Based_3D_Semantic_Occupancy_Prediction_CVPR_2023_paper.pdf 体素表达需要较大的计算量和特别的技巧(如稀疏卷积),BEV表达难以使用平面特征编码所有3D结构。 本文提出三视图(TPV)表达3D场景。为得到空间

    2024年01月23日
    浏览(39)
  • go 上下文:context.Context

    Go语言中的上下文(Context)是一种用于在 Goroutines 之间传递取消信号、截止时间和其他请求范围值的标准方式。 context 包提供了 Context 类型和一些相关的函数,用于在并发程序中有效地传递上下文信息。 在Go语言中,上下文通常用于以下场景: 请求的传递:当一个请求从客户

    2024年02月05日
    浏览(49)
  • 什么是网络——网络能做什么

      个人简介:云计算网络运维专业人员,了解运维知识,掌握TCP/IP协议,每天分享网络运维知识与技能。 座右铭:海不辞水,故能成其大;山不辞石,故能成其高。 个人主页:小李会科技的主页 目录 一.什么是网络 二.网络是什么 三.网络的概念 四.网络的作用  五.实现网络

    2023年04月27日
    浏览(25)
  • go语言可以做什么

    区块链研发工程师 Go 服务器端(数据处理,处理大并发)/游戏软件工程师 Golang分布式/云计算 软件工程师 区块链技术,简称BT(Blockchain technology),也被称之为分布式账本技术,是一种互联网数据库技术,其特点是去中心化、公开透明,让每个人均可参与数据库记录 美团后台流

    2024年02月02日
    浏览(25)
  • Go语言有什么不一样?

    文章首发地址 抛开语法样式不谈,单就类型和规则而言,Go与C99、C11相似之处颇多,这也是我能接受它被冠以“NextC”名号的重要原因。 即便我是个坚定的C拥趸,也不得不承认,它处于简单和复杂的两极。C简单到你每写下一行代码,都能在脑中想象出编译后的模样,指令如

    2024年02月16日
    浏览(30)
  • ZooKeeper能做什么?

    ZooKeeper 是一个高性能、集中化、分布式应用程序协调服务,是 Hadoop 和 Hbase 的重要组件,主要是用来解决分布式应用中用户经常遇到的一些数据管理问题,例如:统一命名服务、统一配置管理、统一集群管理、分布式锁等。 ZooKeeper 提供一种类似目录树结构的数据结构,跟

    2024年02月11日
    浏览(27)
  • Go语言学习Day1:什么是Go?

    名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 创作者:Code_流苏(CSDN) (一个喜欢古诗词和编程的Coder😊) 1、走近Go ①Go语言的Logo Go语言,通常被称为Golang,是一种高效、静态类型的编程语言,旨在简化多核心、网络编程及大型软件项目的开发。Go语言的

    2024年03月22日
    浏览(30)
  • 智能小程序能做什么?

    一. 自定义Tab页 涂鸦提供了丰富的场景化、个性化的 ToC 智能服务,不仅可以快速低成本的自由搭建出更多智能服务,还为你提供了基于小程序技术方案的可自主可控的自定义开发链路,为拓展更多品牌化、个性化、差异化智能服务提供生态基础。 我们支持你 在「智能」Ta

    2024年01月22日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包