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 ...
随机推荐
- 惊不惊喜, 用深度学习 把设计图 自动生成HTML代码 !
如何用前端页面原型生成对应的代码一直是我们关注的问题,本文作者根据 pix2code 等论文构建了一个强大的前端代码生成模型,并详细解释了如何利用 LSTM 与 CNN 将设计原型编写为 HTML 和 ...
- mysql'密码安全
MYSQL数据库的安全配置 MYSQL密码的修改与恢复 MYSQL数据库密码的修改 Mysql5.7以下默认root登录密码为空,安装完成之后首先需要修改root的登录密码. # mysqladm – ...
- python中的pandas的两种基本使用
python中的pandas的两种基本使用2018年05月19日 16:03:36 木子柒努力成长 阅读数:480 一.pandas简介 pandas:panel data analysis(面板数据 ...
- for循环遍历改用map函数
# for url in urls:# url = response.urljoin(url)# print(url)urls = map(lambda url:response.urljoin(ur ...
- React Native Headless JS(后台任务)(转载)
React Native Headless JS(后台任务) Headless JS是一种使用js在后台执行任务的方法.它可以用来在后台同步数据.处理推送通知或是播放音乐等等. JS端的API 首先我 ...
- awr脚本使用dump导出导入
实际工作中,存在这么一种场景.客户现场分析问题,无法立即得出结论,且无法远程服务器,因此对于服务器中的awr信息,如何提取是一个问题,oracle有脚本可以对服务器中以db为单位导出awr基表的dum ...
- Linux 双网卡双网段通信
/********************************************************************************* * Linux 双网卡双网段通信 ...
- 【leetcode】7-ReverseInteger
problem: Reverse Integer 注意考虑是否越界: INT_MAX INT_MIN 32bits or 64bits 调整策略,先从简单的问题开始:
- JavaBasic_06
二维数组 二维数组定义格式 格式1 数据类型 变量名 = new 数据类型m; m表示这个二维数组有多少个一维数组 n表示每一个一维数组的元素个数 格式2 灵活性 数据类型 a = new 数据类型m ...
- c——分解数
把316分解为两个数之和,这两个数分别能被11和13整除 #include <stdio.h> int main() { ,j,k; do { i++; k=-*i; } ); j=k/; ...