我们已经知道WaitGroup可以用于并发控制,但当遇到更复杂的场景时,例如主动取消goroutine或者使超时的goroutine自动退出等,WaitGroup就无能为力。

这个时候,就是context大有用武之地。

context定义了Context类型,它跨API边界和进程之间携带截止日期,取消信号和其他请求范围的值。

对服务器的传入请求应创建一个Context,对服务器的传出调用应接受一个Context。它们之间的函数调用链必须传播Context,或者传递使用WithCancel,WithDeadline,WithTimeout或WithValue创建的派生Context。当取消一个context后,所有从这个context派生的context也会被取消。

WithCancel,WithDeadline和WithTimeout函数接受Context(父)并返回派生的Context(子)和CancelFunc。调用CancelFunc会取消子项及其子项,删除父项对子项的引用,并停止任何关联的计时器。未能调用CancelFunc会泄漏子项及其子项,直到取消父项或计时器触发。 go vet工具检查CancelFuncs是否在所有控制流路径上使用。

使用Contexts的程序应遵循这些规则,以使各包之间的接口保持一致,并启用静态分析工具来检查上下文传播:

  • 不要将Contexts存储在结构类型中;相反,将Context明确传递给需要它的每个函数。Context应该是第一个参数,通常命名为ctx:func DoSomething(ctx context.Context, arg Arg) error { // ... use ctx ... }
  • 即使函数允许,也不要传递nil Context。如果您不确定要使用哪个Context,请传递context.TODO。
  • 仅将context values用于进程间和跨API的请求范围数据,而不是将其作为可选参数传递给函数。
  • 可以将相同的Context传递给在不同goroutine中运行的函数;上下文对于多个goroutine同时使用是安全的。

以上说明来自context包说明,如果感觉翻译的不够清楚,可以查看context的说明。(实在翻译不下去了 = =!)

Context定义如下:

type Context interface {
Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key interface{}) interface{}
}

说了这么多,现在来看下例子吧。

并发控制 Cancel Example

通过使用WithCancel可以主动取消一个或多个goroutine的执行,以实现对并发的控制。

package main 

import (
"context"
"fmt"
"time"
) func PrintTask(ctx context.Context) { for { select { case <- ctx.Done():
return
default:
time.Sleep(2*time.Second)
fmt.Println("A man must walk down many roads.")
} } } func main() { ctx := context.Background()
ctx, cancel := context.WithCancel(ctx) defer cancel() go PrintTask(ctx)
go PrintTask(ctx)
go PrintTask(ctx) time.Sleep(3*time.Second)
fmt.Println("main exit...")
}

WithCancel函数原型如下

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

WithCancel返回两个结果,一个是context(parent的副本,并带有新的Done channel), 一个是cancel函数。

当调用cancel函数或者parent的Done channel关闭时,新返回的Done channel就会被关闭。

例子中,调用cancel函数,关闭了Done channel后,进而PrintTask就会结束。

output

A man must walk down many roads.

A man must walk down many roads.

A man must walk down many roads.

main exit...

并发超时控制 Timeout Example

WithTimeout可以实现并发超时控制,使goroutine执行超时时自动结束。

package main 

import (
"context"
"fmt"
"time"
) func main() { ctx := context.Background()
timeout := 50*time.Millisecond
ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel() done := make(chan int,1) go func() {
// do something
time.Sleep(1*time.Second)
done<- 1
}() select{
case <-done:
fmt.Println("work done on time")
case <-ctx.Done():
// timeout
fmt.Println(ctx.Err())
} fmt.Println("main exit...")
}

例子中,使用WithTimeout()函数,其实现上,直接调用

WithDeadline(parent, time.Now().Add(timeout))

WithDeadline函数定义如下:

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

传入参数:

  • Context类型的变量parent
  • timeout超时时间

返回两个结果:

  • Context类型的变量
  • 取消函数cancel

当出现超时,或者调用取消函数cancel,或者parentDonechannel被关闭时,

新返回的context的Done channel将被关闭。

output:

context deadline exceeded

main exit...

更多参考

golang context学习记录1

golang context学习记录2

Go并发控制--context的使用的更多相关文章

  1. 并发控制--context篇

    目录 1. 前言 2 Context 实现原理 2.1 接口定义 2.1 cancelCtx 2.1.1 Done()接口实现 2.1.2 Err()接口实现 2.1.3 cancel()接口实现 2 ...

  2. golang context学习记录1

    1.前言 一个请求,可能涉及多个API调用,多个goroutine,如何在多个API 之间,以及多个goroutine之间协作和传递信息,就是一个问题. 比如一个网络请求Request,需要开启一些g ...

  3. Go并发控制--WaitGroup篇

    目录 1. 前言 2. 使用WaitGroup控制 2.1 使用场景 2.2 信号量 1.3 WaitGroup 数据结构 2.3.1 Add () 方法 2.3.2 Wait() 2.3.3 Don ...

  4. EntityFramework与TransactionScope事务和并发控制

    最近在园子里看到一篇关于TransactionScope的文章,发现事务和并发控制是新接触Entity Framework和Transaction Scope的园友们不易理解的问题,遂组织此文跟大家共 ...

  5. 数据访问模式:数据并发控制(Data Concurrency Control)

    1.数据并发控制(Data Concurrency Control)简介 数据并发控制(Data Concurrency Control)是用来处理在同一时刻对被持久化的业务对象进行多次修改的系统.当 ...

  6. Entity Framework 乐观并发控制

    一.背景 我们知道,为了防止并发而出现脏读脏写的情况,可以使用Lock语句关键字,这属于悲观并发控制的一种技术,,但在分布式站点下,锁的作用几乎不存在,因为虽然锁住了A服务器的实例对象,但B服务器上的 ...

  7. Kubernetes并发控制与数据一致性的实现原理

    在大型分布式系统中,定会存在大量并发写入的场景.在这种场景下如何进行更好的并发控制,即在多个任务同时存取数据时保证数据的一致性,成为分布式系统必须解决的问题.悲观并发控制和乐观并发控制是并发控制中采用 ...

  8. EF6 Code First 系列 (四):SQLite的DropCreateDatabaseIfModelChanges和乐观并发控制

    没什么好说的,能支持DropCreateDatabaseIfModelChanges和RowVersion的Sqlite谁都想要.EntityFramework7正在添加对Sqlite的支持,虽然EF ...

  9. 深度解密Go语言之context

    目录 什么是 context 为什么有 context context 底层实现原理 整体概览 接口 Context canceler 结构体 emptyCtx cancelCtx timerCtx ...

随机推荐

  1. Vue 项目架构设计与工程化实践

    来源 文中会讲述我从0~1搭建一个前后端分离的vue项目详细过程 Feature: 一套很实用的架构设计 通过 cli 工具生成新项目 通过 cli 工具初始化配置文件 编译源码与自动上传CDN Mo ...

  2. 解决The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.

    SpringMVC中当在浏览器中输入对应的MappingUrl时,报The resource identified by this request is only capable of generat ...

  3. mysql主从复制-读写分离

    mysql主从复制+读写分离 环境:mysql主:193.168.1.1mysql从:193.168.1.2amoeba代理:193.168.1.3########################## ...

  4. Too much thinking! Too much annoying.

    I am now in great demand for an opportunity to yearn for, the ability to express myself, in a maximu ...

  5. 2.3 xpath定位

    2.3 xpath定位 前言    在上一篇简单的介绍了用工具查看目标元素的xpath地址,工具查看比较死板,不够灵活,有时候直接复制粘贴会定位不到.这个时候就需要自己手动的去写xpath了,这一篇详 ...

  6. [转载]PT建站源码(PT服务器原程序)汇总(20100815更新)

    Tbsource官方网站(已失效):http://www.tbsource.com/下载地址:http://www.ipv6bbs.com/thread-5152-1-1.html使用站点:CCFbi ...

  7. dblogin userid ogg ERROR: Unable to connect to database using user ogg

    测试环境,初步配置ogg,添加ogg用户连接数据库,提示无权限报错. 1.0 报错信息 GGSCI (enmo) > dblogin userid ogg,password ogg ERROR: ...

  8. Linux audit安全审计工具

    /********************************************************************** * Linux audit安全审计工具 * 说明: * ...

  9. Python之路,第五篇:Python入门与基础5

    python 循环语句 作用:  根据一定的条件,重复的执行一个或多个语句 两种循环语句: while 语句 for 语句 while 语句: 语法: while    真值表达式: 语句1 ... ...

  10. Python 字符串中 startswith()方法

    Python startswith() 方法用于检查字符串是否是以指定子字符串开头,如果是则返回 True,否则返回 False.如果参数 beg 和 end 指定值,则在指定范围内检查. str.s ...