Golang 利用chan的阻塞机制,实现协程的开始、阻塞、返回控制器
一、使用场景
大背景是从kafka 中读取oplog进行增量处理,但是当我想发一条命令将这个增量过程阻塞,然后开始进行一次全量同步之后,在开始继续增量。
所以需要对多个协程进行控制。
二、使用知识
1. 从一个未初始化的管道读会阻塞
2.从一个关闭的管道读不会阻塞
利用两个管道和select 进行控制
三、上代码
控制器代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | package util import ( "errors" "sync" ) const ( //STOP 停止 STOP = iota //START 开始 START //PAUSE 暂停 PAUSE ) //Control 控制器 type Control struct { ch1 chan struct {} ch2 chan struct {} stat int64 lock sync.RWMutex } var ( //ErrStat 错误状态 ErrStat = errors.New( "stat error" ) ) //NewControl 获得一个新Control func NewControl() *Control { return &Control{ ch1: make( chan struct {}), ch2: nil, stat: START, lock: sync.RWMutex{}, } } //Stop 停止 func (c *Control) Stop() error { c.lock.Lock() defer c.lock.Unlock() if c.stat == START { c.ch2 = nil close(c.ch1) c.stat = STOP } else if c.stat == PAUSE { ch2 := c.ch2 c.ch2 = nil close(c.ch1) close(ch2) c.stat = STOP } else { return ErrStat } return nil } //Pause 暂停 func (c *Control) Pause() error { c.lock.Lock() defer c.lock.Unlock() if c.stat == START { c.ch2 = make( chan struct {}) close(c.ch1) c.stat = PAUSE } else { return ErrStat } return nil } //Start 开始 func (c *Control) Start() error { c.lock.Lock() defer c.lock.Unlock() if c.stat == PAUSE { c.ch1 = make( chan struct {}) close(c.ch2) c.stat = START } else { return ErrStat } return nil } //C 控制管道 func (c *Control) C() <- chan struct {} { c.lock.RLock() defer c.lock.RUnlock() return c.ch1 } //Wait 等待 func (c *Control) Wait() bool { c.lock.RLock() ch2 := c.ch2 c.lock.RUnlock() if ch2 == nil { //通过赋值nil 发送停止推出命令 return false } <-ch2 //会进行阻塞 return true } |
使用代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | for { select { case part, ok := <-c.Partitions(): if !ok { conf.Logger.Error( "get kafka Partitions not ok" , regular.Name) return } go readFromPart(c, part, regular, respChan) case <-regular.C(): //regular 为Control 类 if !regular.Wait() { conf.Logger.Debug( "Stop! " ) return } conf.Logger.Debug( "Start! " ) } } |
这样就可以随时随地的控制工程中的协程
1 2 3 4 | regular := util.NewControl() regular.Pause() regular.Start() regular.Stop() |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?