简介
本例中简单的以我要喝可乐为例, 简单的简述context的使用, 其中比较重要和我觉得context比较妙哉的地方就是继承父context, 即父context取消之后, 也就是done通道关闭了, 其余所有的子context,或者说所有的后代context都会被done掉, 如果你的流程控制中使用的是单纯的一个context也没可以, 通道的基本使用中, 当一个通道被关闭的时候, 对该通道取值会直接返回
我要喝可乐
流程分析
我在房间, 冰箱在厨房,可乐在冰箱里
(1) 我需要到厨房
(2) 打开冰箱门 -> 获得可乐 -> 关闭冰箱门
(3) 回到房间
哪些是可以被中断的
(1) 走到厨房的过程可以被中断
(2) 获取可乐可以被中断, 但需要关闭冰箱门, 不去具体细分打开冰箱门的过程, 打开和关闭冰箱门就不能被中断
(3) 回到房间可以被中断
面向过程代码设计
/* 我在房间, 可乐在厨房的冰箱里, 我要喝可乐 */
func DrinkColaWithCancel() (func()) {
var ctx, cancel = context.WithCancel(context.Background())
go walkToChufang(ctx)
return cancel
}
func walkToChufang(ctx context.Context) {
Println("去厨房的路上...")
select {
case <-time.After(time.Second * 2): // 模拟走到厨房
go chufang(ctx)
case <-ctx.Done():
Println("我在去厨房的路上, 此时被中断...")
}
}
func chufang(ctx context.Context) {
Println("正在厨房...")
select {
case <-time.After(time.Second * 1): // 模拟把手放到冰箱并准备打开的准备时间
go openBingXiang(ctx)
case <-ctx.Done():
Println("我到厨房了, 此时被中断...")
}
}
func openBingXiang(ctx context.Context) {
Println("打开冰箱中...")
select {
case <-time.After(time.Second * 1): // 模拟把手放到冰箱并准备打开的准备时间
go getCola(ctx)
case <-ctx.Done():
Println("我打开冰箱了, 此时被中断...")
go closeBingXiang(ctx)
}
}
func getCola(ctx context.Context) {
Println("取可乐中...")
select {
case <-time.After(time.Second * 1): // 模拟拿可乐过程
go closeBingXiang(ctx)
case <-ctx.Done():
Println("我在拿可乐, 此时被中断...")
go closeBingXiang(ctx)
}
}
func closeBingXiang(ctx context.Context) {
Println("关闭冰箱门中...")
Println("关闭冰箱完毕")
select {
case <-ctx.Done():
Println("关闭冰箱完毕, 此时被中断...")
default:
go backToFangJian(ctx)
}
}
func backToFangJian(ctx context.Context) {
Println("回房间中...")
select {
case <-ctx.Done():
Println("关闭冰箱完毕, 此时被中断...")
default:
finally()
}
}
func finally() {
Println("坐在房间舒服的吹着空调喝着可乐...")
}
效果展示
代码
https://download.csdn.net/download/halo_hsuh/12640503
总结
很多看到的人初觉得没什么, 但异常处理过程中还需要进行完成时的提示, 也就是除了cancel函数之外还有一个finished的通道提示, 或者在finally中处理结束之后的事情, 此处忽略, 但立此提示