Context应用
来源:互联网 发布:js 鼠标滑过div手型 编辑:程序博客网 时间:2024/06/09 13:42
package mainimport ( "context" "fmt" "math/rand" "os" "os/signal" "sync" "syscall" "time")func doFunc1(ctx context.Context, prompt string, wg *sync.WaitGroup) { defer func() { <-time.After(time.Duration(rand.Intn(5000)) * time.Millisecond) fmt.Printf("%v is leaving.\n", prompt) wg.Done() }() if "uno" == prompt { wg.Add(1) newCtx, _ := context.WithCancel(ctx) go doFunc1(newCtx, "tres", wg) } intv := time.NewTicker(time.Second + time.Duration(rand.Intn(1000))*time.Millisecond) for { select { case <-intv.C: fmt.Printf("<%v>tick tick\n", prompt) case <-ctx.Done(): return default: } }}func main() { rand.Seed(time.Now().UnixNano()) defer fmt.Println("bye") ctx, doCancel := context.WithCancel(context.Background()) var wg sync.WaitGroup wg.Add(2) go doFunc1(ctx, "uno", &wg) go doFunc1(ctx, "dos", &wg) sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Kill, os.Interrupt, syscall.SIGTERM) <-sigCh fmt.Println("closing") doCancel() timeoutCtx, _ := context.WithTimeout(context.Background(), 3*time.Second) doneCh := make(chan struct{}, 1) go func() { defer fmt.Println("waited 2000.") wg.Wait() close(doneCh) }() select { case <-doneCh: fmt.Printf("waited done.\n") case <-timeoutCtx.Done(): fmt.Printf("done error: %v\n", timeoutCtx.Err()) }}
- 带“嵌套”的go呼叫. context的cancel行为是带传递性的transitive
- 就算有呼叫者的主动cancel, 也需要子过程主动去查询“自己是否被cancel掉”
- 如果使用sync.WaitGroup的Wait, 可能存在永远的等待.
源码分析: (1.9.2)
Done()完成之后Err()的返回值属于以下两个:
// Canceled is the error returned by Context.Err when the context is canceled.var Canceled = errors.New("context canceled")// DeadlineExceeded is the error returned by Context.Err when the context's// deadline passes.var DeadlineExceeded error = deadlineExceededError{}type deadlineExceededError struct{}
注: error在golang中是一个接口:仅需要实现Error()string即可.
// propagateCancel arranges for child to be canceled when parent is.func propagateCancel(parent Context, child canceler) { if parent.Done() == nil { return // parent is never canceled } if p, ok := parentCancelCtx(parent); ok { p.mu.Lock() if p.err != nil { // parent has already been canceled child.cancel(false, p.err) } else { if p.children == nil { p.children = make(map[canceler]struct{}) } p.children[child] = struct{}{} } p.mu.Unlock() } else { go func() { select { case <-parent.Done(): child.cancel(false, parent.Err()) case <-child.Done(): } }() }}
建立context对象初期就会去创建一个goroutine, 用select挂在parent和自己的done channel上。
// A canceler is a context type that can be canceled directly. The// implementations are *cancelCtx and *timerCtx.type canceler interface { cancel(removeFromParent bool, err error) Done() <-chan struct{}}
WithCancel除了创建对象也要返回canceler, canceler就是对 cancelContext对象上调用cancel方法:
cancel之后总是会标记error, 所以canceler可以重复调用。
原文链接:
https://siadat.github.io/post/context
阅读全文
0 0
- Context应用
- Context的应用场景
- Context应用场景
- Context的应用场景
- 关于web应用上下文Context
- Android Context应用上下文详解
- 关于web应用上下文Context
- Tomcat中对Context应用
- Context上下文的一些应用
- Android--应用全局获取Context
- Application context和Activity context的区别及应用
- Tomcat 6多应用的Context配置
- Tomcat 6多应用的Context配置
- J2EE中的Config与Context参数应用
- jboss设置web应用的context root
- jboss设置web应用的context root
- php file_get_contents中context选项的应用
- Android -- Context(Application的应用)
- 蓝牙5.0发布(新特性速览)
- Struts2和Spring的整合代码截图
- 画家与黑客(语录)
- git 生成patch并打入主干
- python索引问题
- Context应用
- tomcat 启动项目时出现 ZipException: error in opening zip file
- 为什么那么多人都选择通过培训来学习Java?
- 整合hibernate与JPA
- git error Large files detected解决办法
- Python web 框架 Flask 入门 macOS 下实践记录
- kafka学习(1)
- html定时刷新
- 今天