Golang 语言标准库 context 包控制 goroutine

简介: Golang 语言标准库 context 包控制 goroutine

01

介绍


在 Go1.7 中,标准库加入了 context 包,context 包定义了一个 Context (上下文)类型,可以在 Api 之间和进程之间传递信息,还提供了超时(timeout)和取消(cancel)机制。


Go 标准库中,database/sql,net,net/http 等包中都使用了 Context。


在 Go 应用开发中,一般用于请求链路中传递上下文信息,控制子 goroutine 等场景中。


02

Context 接口



var (
  background = new(emptyCtx)
  todo       = new(emptyCtx)
)
func Background() Context {
  return background
}
func TODO() Context {
  return todo
}


context 包定义了一个 Context 接口,包含 4 个方法:

  • Deadline() (deadline time.Time, ok bool)
    Deadline 方法返回结果有两个,第一个是截止时间,到了这个截止时间,Context 会自动取消;第二个是一个 bool 类型的值,如果 Context 没有设置截止时间,第二个返回结果是 false,如果需要取消这个 Context,就需要调用取消函数。
  • Done() <-chan struct{}
    Done 方法返回一个只读的 channel 对象,类型是 struct{},在 goroutine 中,如果 Done 方法返回的结果可以被读取,代表父 Context 调用了取消函数。
  • Err() error
    Err 方法返回 Context 被取消的原因。
  • Value(key interface{}) interface{}
    Value 方法返回此 Context 绑定的值。它是一个 kv 键值对,通过 key 获取对应 value 的值。


03

创建 Context


context 包中包含两个生成顶层 Context 的方法:

  • func Background() Context
    Background 方法一般用于 main 函数,init 函数,测试和创建根 Context 的时候。
  • func TODO() Context
    TODO 方法,当不清楚使用哪个上下文,可以使用 TODO 方法。

这两个方法都是返回一个非 nil,空 Context,没有任何值,不会被 cancel,不会超时,没有截止日期。实际上,这两个方法的底层实现是一样的。


var (
  background = new(emptyCtx)
  todo       = new(emptyCtx)
)
func Background() Context {
  return background
}
func TODO() Context {
  return todo
}

这两个方法都是 emptyCtx 的指针类型,是一个不可取消,没有设置截止时间,没有任何值得 Context。


type emptyCtx int
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
  return
}
func (*emptyCtx) Done() <-chan struct{} {
  return nil
}
func (*emptyCtx) Err() error {
  return nil
}
func (*emptyCtx) Value(key interface{}) interface{} {
  return nil
}
func (e *emptyCtx) String() string {
  switch e {
  case background:
    return "context.Background"
  case todo:
    return "context.TODO"
  }
  return "unknown empty Context"
}


04

CancelFunc 类型



type CancelFunc func()

CancelFunc 用于主动让 goroutine 停止。多个goroutine 可以同时调用 CancelFunc。在第一个调用之后,随后对 CancelFunc 的调用什么也不做。


05

函数


创建了顶层 Context,想要创建子 Context,可以使用以下方法:

  • WithCancel
    WithCancel 方法,基于父 Context,接收一个父 Context 参数,生成一个新的子 Context,和一个 cancel 函数,用于取消 Context。
  • WithDeadline
    WithDeadline 方法,基于父 Context,接收一个父 Context 参数,和一个截止时间的参数,生成一个新的子 Context,和一个 cancel 函数,可以使用 cancel 函数取消 Context,也可以等到截止时间,自动取消 Context。
  • WithTimeout
    WithTimeout 方法,基于父 Context,接收一个父 Context 参数,和一个超时时间的参数,生成一个新的子 Context,和一个 cancel 函数,可以使用 cancel 函数取消 Context,也可以等到超时时间,自动取消 Context。
  • WithValue
    WithValue 方法,基于父 Context,生成一个新的子 Context,携带了一个 kv 键值对,一般用于传递上下文信息。



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


示例代码:


var name string
func main () {
  // ctx, cancle := context.WithCancel(context.Background())
  // d := time.Now().Add(time.Second * 2)
  // ctx, cancle := context.WithDeadline(context.Background(), d)
  ctx, cancle := context.WithTimeout(context.Background(), time.Second * 2)
  valueCtx := context.WithValue(ctx, name, "lucy")
  go work(valueCtx)
  time.Sleep(time.Second * 3)
  fmt.Println("停止工作。")
  cancle()
  time.Sleep(time.Second * 5)
}
func work(ctx context.Context) {
  for {
    select {
    case <- ctx.Done():
      fmt.Println(ctx.Value(name), "工作结束!")
      return
    default:
      fmt.Println(ctx.Value(name), "工作中。")
      time.Sleep(time.Second * 1)
    }
  }
}


06

规范


  • 不要将上下文存储在结构类型中;而是将上下文以参数形式传递给需要它的函数。并且 Context 应该是第一个参数,该参数通常命名为 ctx。

  • 即使函数允许,也不要传递nil Context 的参数。如果不确定使用哪个上下文,就使用 context.TODO。

  • 可以将相同的 Context 上下文传递给在不同 goroutine 中运行的函数。上下文是线程安全的,可由多个 goroutine 同时使用。


07

总结


Context 一般用于控制 goroutine,使用 Context 主动取消 goroutine 的运行。除此之外,关于控制 goroutine,我们还可以使用 WaitGroup 和 channel 被动取消 goroutine。





目录
相关文章
|
1月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
130 1
|
6月前
|
Go
在golang中发起http请求以获取访问域名的ip地址实例(使用net, httptrace库)
这只是追踪我们的行程的简单方法,不过希望你跟着探险家的脚步,即使是在互联网的隧道中,也可以找到你想去的地方。接下来就是你的探险之旅了,祝你好运!
307 26
|
8月前
|
Go 开发者
go-carbon v2.6.0 重大版本更新,轻量级、语义化、对开发者友好的 golang 时间处理库
carbon 是一个轻量级、语义化、对开发者友好的 Golang 时间处理库,提供了对时间穿越、时间差值、时间极值、时间判断、星座、星座、农历、儒略日 / 简化儒略日、波斯历 / 伊朗历的支持
178 3
|
9月前
|
网络协议 测试技术 Linux
Golang 实现轻量、快速的基于 Reactor 模式的非阻塞 TCP 网络库
gev 是一个基于 epoll 和 kqueue 实现的高性能事件循环库,适用于 Linux 和 macOS(Windows 暂不支持)。它支持多核多线程、动态扩容的 Ring Buffer 读写缓冲区、异步读写和 SO_REUSEPORT 端口重用。gev 使用少量 goroutine,监听连接并处理读写事件。性能测试显示其在不同配置下表现优异。安装命令:`go get -u github.com/Allenxuxu/gev`。
199 0
|
12月前
|
JSON Go 开发者
go-carbon v2.5.0 发布,轻量级、语义化、对开发者友好的 golang 时间处理库
carbon 是一个轻量级、语义化、对开发者友好的 Golang 时间处理库,提供了对时间穿越、时间差值、时间极值、时间判断、星座、星座、农历、儒略日 / 简化儒略日、波斯历 / 伊朗历的支持。
256 4
|
存储 Cloud Native Shell
go库介绍:Golang中的Viper库
Viper 是 Golang 中的一个强大配置管理库,支持环境变量、命令行参数、远程配置等多种配置来源。本文详细介绍了 Viper 的核心特点、应用场景及使用方法,并通过示例展示了其强大功能。无论是简单的 CLI 工具还是复杂的分布式系统,Viper 都能提供优雅的配置管理方案。
314 6
|
前端开发 中间件 Go
实践Golang语言N层应用架构
【10月更文挑战第2天】本文介绍了如何在Go语言中使用Gin框架实现N层体系结构,借鉴了J2EE平台的多层分布式应用程序模型。文章首先概述了N层体系结构的基本概念,接着详细列出了Go语言中对应的构件名称,包括前端框架(如Vue.js、React)、Gin的处理函数和中间件、依赖注入和配置管理、会话管理和ORM库(如gorm或ent)。最后,提供了具体的代码示例,展示了如何实现HTTP请求处理、会话管理和数据库操作。
210 0
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
603 4
Golang语言之管道channel快速入门篇
|
Go
Golang语言文件操作快速入门篇
这篇文章是关于Go语言文件操作快速入门的教程,涵盖了文件的读取、写入、复制操作以及使用标准库中的ioutil、bufio、os等包进行文件操作的详细案例。
229 4
Golang语言文件操作快速入门篇
|
Go
Golang语言之gRPC程序设计示例
这篇文章是关于Golang语言使用gRPC进行程序设计的详细教程,涵盖了RPC协议的介绍、gRPC环境的搭建、Protocol Buffers的使用、gRPC服务的编写和通信示例。
498 3
Golang语言之gRPC程序设计示例

推荐镜像

更多