教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 go: WaitGroup 原理: 直到最底层

go: WaitGroup 原理: 直到最底层

发布时间:2022-02-08   编辑:jiaochengji.com
教程集为您提供go: WaitGroup 原理: 直到最底层等资源,欢迎您收藏本站,我们将为您提供最新的go: WaitGroup 原理: 直到最底层资源
<ul><li>参考 <ul><li>[好文](https://draveness.me/golang/docs/part3-runtime/ch06-concurrency/golang-sync-primitives/)</li></ul></li><li>经典用法
https://gobyexample.com/waitgroups <ul><li>构造wg</li></ul><ul><li>wg.Add(1)</li></ul><ul><li>defer wg.Done(),也就是wg.Add(-1)</li></ul><ul><li>并行搞起</li></ul><ul><li>wg.wait()</li></ul></li><li>WaitGroup重要变量:counter,waiter,sema(信号量) <ul><li>推论:counter==0认为是并发任务执行完毕。 <ul><li>为什么?整个流程上来就是Add把counter 1,正常流程会把Add全部执行完再wait。任何情况下,只要wait发现count==0,那就是并行任务执行完了。</li></ul></li></ul></li><li>Add(delta) <ul><li>CAS counter delta</li></ul><ul><li>counter > 0 或者 waiter == 0 return(为啥这么写?return是为了不执行后面的sema操作(通知等待的goroutine)。counter>0或者waiter==0不执行是为啥?waiter==0都没人在等,当然不需要执行后面的通知goroutine,counter>0说明还没干完活呢没把counter减到0呢,也没必要去执行后面的通知) <ul><li>其实可以看后面的注释:当前的goroutine,当waiters>0的时候把counter设置成了0。(counter==0任务执行完了且有人在等待咱们唤醒,那就要唤醒)(没有return的情况下,说明v==0 && w !=0)。说明了啥呢?现在不可能有并发改state了。为啥? <ul><li>Adds不能跟Wait并发发生(看经典用法,按常理,肯定是一个一个add完最后才wait的)</li></ul><ul><li>Wait不会增加waiter如果它看到counter==0</li></ul></li></ul></li></ul><ul><li>重置waiter数量为0</li></ul><ul><li>对sema执行waiter次 runtime_SemRelease</li></ul></li><li>Wait() <ul><li>死循环 <ul><li>获取一遍counter和waiter</li></ul><ul><li>counter == 0,return。(counter归零了==执行完了,可以直接返回,否则说明还没执行完,需要睡一会等人来叫醒我)</li></ul><ul><li>if CAS waiter 1 成功 <ul><li>对sema执行1次runtime_Semacquire(睡吧等人叫醒我)</li></ul><ul><li>返回</li></ul></li></ul></li></ul></li><li>这过程中又涉及俩底层玩意儿 <ul><li>runtime_SemRelease(叫醒人)
原子 1,然后通知等待的goroutine(如果一个goroutine在获取过程中阻塞了)</li></ul><ul><li>runtime_Semacquire(睡吧等人叫醒我)
​阻塞等待直到信号量>0然后原子-1</li></ul></li><li>所以把整个官方例子串起来那就是(假设add两遍) <ul><li>wg.Add(1) <ul><li>counter=1,waiter=0,返回,sema没改=0</li></ul></li></ul><ul><li>go funcA() {并行干点A事情; }</li></ul><ul><li>wg.Add(1) <ul><li>counter=2,waiter=0,返回,sema没改=0</li></ul></li></ul><ul><li>go funcB() {并行干点B事情; }</li></ul><ul><li>wg.wait() <ul><li>CAS waiter 1 = 1</li></ul><ul><li>runtime_Semacquire,阻塞等待。</li></ul></li></ul><ul><li>A干完了wg.Add(-1) <ul><li>counter-1=1,counter>0 return</li></ul></li></ul><ul><li>B干完了wg.Add(-1) <ul><li>counter-1=0,waiter=1,没有直接返回</li></ul><ul><li>重置waiter=0</li></ul><ul><li>执行1次runtime_SemRelease。 <ul><li>原子sema 1=1,通知等待的goroutine(在wait的那哥们)</li></ul></li></ul></li></ul><ul><li>wg.wait()收到通知,信号量>0了,原子sema-1=0</li></ul></li><li>更底层怎么实现的?/usr/local/go/src/runtime/sema.go <ul><li>runtime_SemRelease(叫醒人)
原子 1,然后通知等待的goroutine(如果一个goroutine在获取过程中阻塞了)</li></ul><ul><li>runtime_Semacquire(睡吧等人叫醒我)【其实这是很多锁的统一套路。比如Java。没啥可说的,这就是沉淀下来的经验,不好深究每一行是为什么】https://blog.csdn.net/waltonhuang/article/details/110797972
​阻塞等待直到信号量>0然后原子-1 <ul><li>easycase:直接看一下sema,如果==0,获取失败,否则,原子-1成功则获取成功。</li></ul><ul><li>hardercase: <ul><li>死循环: <ul><li>增加waiter数量</li></ul><ul><li>再试一下获取,成功就返回</li></ul><ul><li>排队</li></ul><ul><li>休眠</li></ul></li></ul></li></ul></li></ul></li><li> </li></ul> 到此这篇关于“go: WaitGroup 原理: 直到最底层”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
go: WaitGroup 原理: 直到最底层
Go WaitGroup实现原理
字节跳动的 Go 语言面试会问哪些问题?
golang WaitGroup源码解析
golang 深入浅出之 goroutine 理解
golang goroutine 通知_深入golang之---goroutine并发控制与通信
Golang sync.WaitGroup源码详细分析
golang语言异步通信之WaitGroup
Go语言基础(3)
golang 基础知识点

[关闭]
~ ~