17 | SingleFlight 和 CyclicBarrier:请求合并和循环栅栏该怎么用?
该思维导图由 AI 生成,仅供参考
请求合并 SingleFlight
- 深入了解
- 翻译
- 解释
- 总结
本文深入介绍了两个重要的并发原语:SingleFlight和CyclicBarrier。SingleFlight用于合并并发请求,减少对下层服务的压力,适用于缓存系统中,能提高系统性能。其实现原理是使用互斥锁和Map来实现,并在处理多个goroutine同时调用同一个函数时,只让一个goroutine去调用这个函数。CyclicBarrier用于控制一组请求同时执行的数据结构,适合用在“固定数量的goroutine等待同一个执行点”的场景中。它可以被重复使用,不像WaitGroup需要小心翼翼避免panic。文章还介绍了CyclicBarrier的初始化方法和使用方式,并给出了一个经典的并发编程题目,展示了CyclicBarrier的应用场景和功能。最后,文章给出了H2O制造工厂的具体实现,通过代码示例展示了CyclicBarrier的使用方法。整体来说,本文详细介绍了SingleFlight和CyclicBarrier的特点、应用场景和实现原理,对于并发编程感兴趣的读者具有很高的参考价值。文章还提出了思考题,引发读者思考并发编程中的更多可能性。建议读者多了解并发原语,丰富知识库,提升在并发场景中的应对能力。
《Go 并发编程实战课》,新⼈⾸单¥59
全部留言(20)
- 最新
- 精选
- 杜鑫谢谢老师的文章!第一次知道有这两种并发原语,不管之后工作能不能用到,这都是对个人眼界的开阔! ps:老师的文章几乎都是一篇顶两篇,刚订阅的时候还担心课程内容太少,现在一看担心完全是多余的,这段时间读了老师的文章之后,个人对go并发知识了解更深刻了,谢谢老师!
作者回复: 加油!
2020-11-1913 - 无名氏CyclicBarrier 那个测试例子没有看懂,2个H,一个O顺序怎么保证是HHO😅
作者回复: hho,hoh,ohh,都可以,只有保证是一个水分子
2022-03-1921 - Fan老师,在你github地址 https://github.com/smallnest/dive-to-gosync-workshop/tree/master/7.orchestration/water中没有搜到WaitGroup版本的H2O的例子,但是按照你正文中WaitGroup版本实现H2O,有报错panic: sync: WaitGroup is reused before previous Wait has returned 。请问老师这应该怎么解决呢?很困惑,望老师指点。
作者回复: https://github.com/smallnest/dive-to-gosync-workshop/tree/master/7.orchestration/water
2020-12-2821 - Fan老师,感觉你上面用waitGroup实现这个H2O的例子有问题的。我这边运行都panic的。
作者回复: 报什么错?这些例子都是我运行过的,你也可以到github上搜我的一个项目叫workshop的代码
2020-12-2541 - 伟伟package main import ( "context" "github.com/marusama/cyclicbarrier" "golang.org/x/sync/semaphore" ) type H2O2 struct { semaH *semaphore.Weighted semaO *semaphore.Weighted b cyclicbarrier.CyclicBarrier } func New() *H2O2 { return &H2O2{ semaH: semaphore.NewWeighted(2), semaO: semaphore.NewWeighted(2), b: cyclicbarrier.New(4), } } func (h2o2 *H2O2) hydrogen(releaseHydrogen func()) { h2o2.semaH.Acquire(context.Background(), 1) releaseHydrogen() h2o2.b.Await(context.Background()) h2o2.semaH.Release(1) } func (h2o2 *H2O2) oxygen(releaseOxygen func()) { h2o2.semaO.Acquire(context.Background(), 1) releaseOxygen() h2o2.b.Await(context.Background()) h2o2.semaO.Release(1) }
作者回复: ������������
2020-11-231 - 白开d水为什么在 h2o.semaH.Acquire(context.Background(), 1) 1不能换成2呢,直接请求2个资源?
作者回复: 每个goroutine只能出一个原子
2023-03-23归属地:北京2 - 李晓清package main import ( "context" "fmt" "time" "github.com/marusama/cyclicbarrier" ) var result chan string = make(chan string, 4) var barrier = cyclicbarrier.NewWithAction(4, func() error { fmt.Println(<-result, <-result, <-result, <-result) return nil }) var h = func() { for { time.Sleep(1 * time.Second) result <- "H" barrier.Await(context.TODO()) } } var o = func() { for { time.Sleep(1 * time.Second) result <- "O" barrier.Await(context.TODO()) } } func main() { go h() go h() go o() go o() select {} }
作者回复: 如果没有tome.sleep,或者sleep很短,还可以吗
2023-03-17归属地:北京 - Geek8956老师,请问循环栏栅和cond并发原语有什么区别?他们都可以让多个协程等待某个条件满足,然后并发的开始执行。
作者回复: 循环栅栏的重点是循环,重用
2021-11-29 - 老纪在CyclicBarrier中,是需要一组goroutine都执行到Await()方法后,才会都向下执行否则就会阻塞在Await()方法上吗
作者回复: 是的
2020-12-08 - Linuxer感觉自已Go刚刚入门,我确实也才学习一周左右,看着挺爽,写起来还是不顺手,还得多练习,老师能否给我们这些打算转Go的新手一些建议,谢谢
作者回复: 多实践,在项目中锻炼,很快就顺手了
2020-11-20