Go并发控制--context的使用
我们已经知道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,或者parent
的Done
channel被关闭时,
新返回的context的Done
channel将被关闭。
output:
context deadline exceeded
main exit...
更多参考
golang context学习记录1
golang context学习记录2
Go并发控制--context的使用的更多相关文章
- 并发控制--context篇
目录 1. 前言 2 Context 实现原理 2.1 接口定义 2.1 cancelCtx 2.1.1 Done()接口实现 2.1.2 Err()接口实现 2.1.3 cancel()接口实现 2 ...
- golang context学习记录1
1.前言 一个请求,可能涉及多个API调用,多个goroutine,如何在多个API 之间,以及多个goroutine之间协作和传递信息,就是一个问题. 比如一个网络请求Request,需要开启一些g ...
- Go并发控制--WaitGroup篇
目录 1. 前言 2. 使用WaitGroup控制 2.1 使用场景 2.2 信号量 1.3 WaitGroup 数据结构 2.3.1 Add () 方法 2.3.2 Wait() 2.3.3 Don ...
- EntityFramework与TransactionScope事务和并发控制
最近在园子里看到一篇关于TransactionScope的文章,发现事务和并发控制是新接触Entity Framework和Transaction Scope的园友们不易理解的问题,遂组织此文跟大家共 ...
- 数据访问模式:数据并发控制(Data Concurrency Control)
1.数据并发控制(Data Concurrency Control)简介 数据并发控制(Data Concurrency Control)是用来处理在同一时刻对被持久化的业务对象进行多次修改的系统.当 ...
- Entity Framework 乐观并发控制
一.背景 我们知道,为了防止并发而出现脏读脏写的情况,可以使用Lock语句关键字,这属于悲观并发控制的一种技术,,但在分布式站点下,锁的作用几乎不存在,因为虽然锁住了A服务器的实例对象,但B服务器上的 ...
- Kubernetes并发控制与数据一致性的实现原理
在大型分布式系统中,定会存在大量并发写入的场景.在这种场景下如何进行更好的并发控制,即在多个任务同时存取数据时保证数据的一致性,成为分布式系统必须解决的问题.悲观并发控制和乐观并发控制是并发控制中采用 ...
- EF6 Code First 系列 (四):SQLite的DropCreateDatabaseIfModelChanges和乐观并发控制
没什么好说的,能支持DropCreateDatabaseIfModelChanges和RowVersion的Sqlite谁都想要.EntityFramework7正在添加对Sqlite的支持,虽然EF ...
- 深度解密Go语言之context
目录 什么是 context 为什么有 context context 底层实现原理 整体概览 接口 Context canceler 结构体 emptyCtx cancelCtx timerCtx ...
随机推荐
- react 学习笔记 npm 命令
第一步: cnpm install --save react react-dom babelify babel-preset-react 第二步: 安装es2015 cnpm install babe ...
- REST是什么?
REST -- REpresentational State Transfer 直接翻译:表现层状态转移. @Ivony 老师的一句话概括很精辟: 用URL定位资源,用HTTP动词(GET,POS ...
- Spring Boot 揭秘与实战(二) 数据存储篇 - MySQL
文章目录 1. 环境依赖 2. 数据源3. 脚本初始化 2.1. 方案一 使用 Spring Boot 默认配置 2.2. 方案二 手动创建 4. 使用JdbcTemplate操作5. 总结 4.1. ...
- Can't locate find.pl in @INC (@INC contains: /etc/perl xxxx) at perlpath.pl line 7.
/********************************************************************** * Can't locate find.pl in @I ...
- flask中的request和response
1.request 1.request的常用成员 1.scheme : 获取请求方案(协议) 2.method : 获取本期请求的请求方式(重点) 3.args : 获取使用get请求方式提交的数据 ...
- websocket介绍 以及 vue websocket使用案例
1 介绍: https://www.zhihu.com/question/20215561 2 案例: https://www.jianshu.com/p/0d20a032d0ec (坑说明). ht ...
- day 017面向对象-反射
主要内容: isinstance, type, issubclass( 内置函数) 区分函数和方法 反射 一 ( isinstance, type, issubclass) isinstance ...
- 如何解决VMware 12 安装Ubuntu 16.04时无网络连接问题
刚安装玩Ubuntu,打开后上网没有网络连接 ,点击右上角的数据连接,显示已经启动联网,但是用火狐还是无法上网: 解决方法如下: 先查看虚拟机的网络适配器:点击虚拟机左上角的编辑,里面有个网络适配器 ...
- 神坑,使用gcc对opencv重编译
工具 cmake-3.9.1 opencv-3.3.0 gcc-6.3.0 前几天为了装eclipse的CDT,把minggw里的make改了,今天突然想学opencv,可是只找到了vc版本,千辛万 ...
- hdu3338 Kakuro Extension 最大流
If you solved problem like this, forget it.Because you need to use a completely different algorithm ...