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类型的变量parenttimeout超时时间
返回两个结果:
Context类型的变量- 取消函数cancel
当出现超时,或者调用取消函数cancel,或者parent的Donechannel被关闭时,
新返回的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 ...
随机推荐
- c#继承中的函数调用实例
using System; namespace Test { public class Base { public void Print() { ...
- 3-log4j2之输出日志到文件
一.添加maven依赖 <dependencies> <dependency> <groupId>org.apache.logging.log4j</grou ...
- SpringMVC实现从磁盘中下载文件
除了文件的上传我们还需要从磁盘下载 实现文件的下载只要编写一个控制器,完成读写操作和响应头和数据类型的设置就可以了 下面演示的是从G盘imgs文件夹中下载文件 具体代码如下 package com.c ...
- live555 学习资料
下载源码 http://www.live555.com/liveMedia/public/live555-latest.tar.gz 安装tar xzf live555-latest.tar.gz c ...
- js--单例设计模式
通过闭包方法实现: var creatE=(function(){ var obj; return function(){ if(!obj){ } reutrn obj; } })();//自调用 c ...
- Win2003可用序列号(标准版与企业版)
通用性好的win2003序列号: (推荐先用这个里面的)FJ8DH-TQPYG-9KFHQ-88CB2-Y7V3Y GRD4P-FTQQF-JCDM8-4P6JK-PFG7M JD7JX-KCDTH- ...
- $interpolateProvider
angular.module('emailParser', []) .config(['$interpolateProvider', function($interpolateProvider) { ...
- 《网页文档/文字复制方法大全》 - imsoft.cnblogs
<网页文档/文字复制方法大全> 一: 1.首先,找到自己要的文档. 2.文章题目复制,在搜索引擎的框框里输入:site:wenku.baidu.com "题目"/sit ...
- golang channel 总结
1.未初始化的channel读,阻塞 package main import ( "fmt" "time" ) func main() { var ch cha ...
- quartz定时任务及时间设置
quartz 定时任务时间设置1.这些星号由左到右按顺序代表 : * * * * * * * ...