GO中sync包自由控制并发示例详解
来源:脚本之家
时间:2023-01-07 12:12:10 391浏览 收藏
知识点掌握了,还需要不断练习才能熟练运用。下面golang学习网给大家带来一个Golang开发实战,手把手教大家学习《GO中sync包自由控制并发示例详解》,在实现功能的过程中也带大家重新温习相关知识点,温故而知新,回头看看说不定又有不一样的感悟!
资源竞争
channel 常用于并发通信,要保证并发安全,主要使用互斥锁。在并发的过程中,当一个内存被多个 goroutine 同时访问时,就会产生资源竞争的情况。这块内存也可以称为共享资源。
并发时对于共享资源必然会出现抢占资源的情况,如果是对某资源的统计,很可能就会导致结果错误。为保证只有一个协程拿到资源并操作它,可以引入互斥锁 sync.Mutex。
sync.Mutex
互斥锁,指的是并发时,在同一时刻只有一个协程执行某段代码,其他协程只有等待该协程执行完成后才能继续执行。
var (sum int mutex sync.Mutex) func add(i int){ mutex.Lock() sum+=i mute.Unlock() }
使用 mutex 加锁保护 sum+ =i 的代码片段,这样这个片段区就无法同时被多个协程访问,当有协程进入该片段区,那其他的协程就只有等待,以此保证临界区的并发安全。
sync.Mutex 只有 Lock()和 Unlock() 方法,它们是成对存在的,且Lock后一定要执行Unlock进行释放锁。所以可以使用 defer 语句释放锁,以保证锁一定会被释放。
func add(i int){ mutex.Lock() defer mutex.Unlock() sum += i }
sync.RWMutex
上面例子是对 sum 写操作时使用sync.Mutex 保证并发安全,当多个协程进行读取操作时,避免因并发产生读取数据不正确,也是可以使用互斥锁 sync.Mutex。
func getSum(){ mutex.Lock() defer mutex.Unlock() b:=sum return b }
多个协程 goroutine 同时读写的资源竞争问题解决,还需要考虑性能问题,每次读写共享资源都加锁,也会导致性能低。
多个协程并发进行读写时会遇到以下情况:
- 写时不能同时读,易读到脏数据
- 读时不能同时写,因为会导致结果不一致
- 读时同时写,因数据不变,无论多少个 goroutine 读都是并发安全
使用读写锁 sync.RWMutex 优化代码:
var mutex sync.RWMutex func readSum() int { mutex.RLock() defer mutex.RUnlock() b := sum return b }
读写锁的性能比互斥锁性能好。
sync.WaitGroup
为了能够监听所有的协程的执行,一旦所有的goroutine 都执行完成,程序应当及时退出节省时间提高性能。通过使用 sync.WaitGroup 来解决。使用步骤如下:
- 声明一个 sync.WaitGroup ,通过 add 方法增加计数器值,有几个协程就计算几个
- 每个协程结束后就调用 Done 方法,主要是让计数器减1
- 最后调用 Wait 方法一直等待,直到计数器为 0 时,所有跟踪的协程都执行完毕
func run() { var wg sync.WaitGroup wg.Add(100) for i := 0; i通过 sync.WaitGroup 可以很好地跟踪协程.
sync.Once
sync.Once 作用是让代码只执行一次。详细使用是调用方法 once.Do 方法,具体实现:
func main(){ var once sync.once oneFunc := func(){ println("once func") } once.Do(oneFunc) }sync.Once 适用于创建某个对象的单例、只加载一次的资源等只执行一次的场景。
sync.Cond
使用 sync.WaitGroup 主要是控制等待所有的协程都执行完毕,才最终完成。但是当遇到场景是,只有等待所有条件都准备好才开始。sync.Cond 相当于发号施令,只有通知执行所有的协程才可以执行,重点是所有协程需等待唤醒才可以开始。
所以 sync.Cond 具有阻塞协程和唤醒协程的功能。详细的用法:
- 通过 sync.NewCond 函数生成一个 *sync.Cond,用于阻塞和唤醒协程
- 调用 cond.Wait() 方法阻塞当前协程等待,需要注意调用 cond.Wait() 方法要加锁
- 调用 cond.Broadcast() 后所有协程才开始执行
func run() { cond := sync.NewCond(&sync.Mutex{}) var wg sync.WaitGroup wg.Add(101) for i := 0; i < 100; i++ { go func(num int) { defer wg.Done() fmt.Println(num, "号正在 awaiting......") cond.L.Lock() cond.Wait() //等待所有协程准备完成 fmt.Println(num, "号开始跑……") cond.L.Unlock() }(i) } // 等待所有的协程都进入 wait 状态 time.Sleep(2*time.Second) go func() { defer wg.Done() // 所有都准备完成,开始 cond.Broadcast() }() // 防止函数提前返回退出 wg.Wait() }
本篇关于《GO中sync包自由控制并发示例详解》的介绍就到此结束啦,但是学无止境,想要了解学习更多关于Golang的相关知识,请关注golang学习网公众号!
-
164 收藏
-
208 收藏
-
500 收藏
-
334 收藏
-
417 收藏
-
309 收藏
-
225 收藏
-
485 收藏
-
233 收藏
-
322 收藏
-
181 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 秀丽的金鱼
- 这篇技术贴真及时,太细致了,感谢大佬分享,码住,关注老哥了!希望老哥能多写Golang相关的文章。
- 2023-05-06 02:09:23
-
- 贪玩的唇膏
- 这篇技术贴太及时了,很详细,很好,已加入收藏夹了,关注博主了!希望博主能多写Golang相关的文章。
- 2023-03-12 08:41:40
-
- 粗暴的小松鼠
- 感谢大佬分享,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢博主分享文章内容!
- 2023-01-24 09:51:51
-
- 自信的小白菜
- 这篇技术文章真及时,好细啊,受益颇多,码起来,关注楼主了!希望楼主能多写Golang相关的文章。
- 2023-01-09 03:10:20
-
- 怕孤独的大山
- 这篇技术贴太及时了,太全面了,很好,已加入收藏夹了,关注up主了!希望up主能多写Golang相关的文章。
- 2023-01-09 00:03:02
-
- 陶醉的项链
- 很有用,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢博主分享博文!
- 2023-01-08 14:04:29