等待组

  • 在此之前,我们让主协程等待子协程结束的方式都是睡眠,睡足子协程需要的时间,这种方式显然是不理想的!
  • 等待组(sync.WaitGroup)的原理是:每增加一个子协程,就向等待组中+1,每结束一个协程,就从等待组中-1,主协程会阻塞等待直到组中的协程数等于0为止;
  • 这种方式可以令主协程恰好结束在最后一个子协程结束的时间点上,Perfect!

互斥锁案例1

  • 在很多情境中,数据是不允许并发修改的;
  • 典型的案例如银行账户,银行卡在存取的过程中,存折是不允许在同一时间进行存取操作的,例如卡刚刚取走500,在查询余额时恰好存折又存入500,银行卡在查询余额时会误以为银行并没有扣款,这显然是应该避免的!
  • 所以我们不允许银行卡和存折并发地执行存取操作,必须同步串行有先后地执行存取,这样才不会带来脏读和幻读;
  • 我们可以通过抢互斥锁(sync.Mutex)的方式来强制存取操作同步;
  • 互斥锁的原理是:对于有必要强制同步串行的任务,我们规定它只有得到互斥锁才有执行权,而全局只有一把互斥锁,谁先抢到谁就获得任务执行权,任务进行的过程中如果有其它协程想要得到执行权,它必须阻塞等待至当前任务协程释放同步锁;
  • 下面的例子中,银行卡无论谁先抢到资源锁,都立刻对同步锁进行锁定(mt.Lock()),在其存取操作没有结束之前,另一方必须阻塞等待直至前者将互斥锁释放(mt.Unlock());
package mainimport ("fmt""time""sync"
)func main() {//必须保证并发安全的数据type Account struct {money float32}var wg sync.WaitGroupaccount := Account{1000}fmt.Println(account)//资源互斥锁(谁抢到锁,谁先访问资源,其他人阻塞等待)//全局就这么一把锁,谁先抢到谁操作,其他人被阻塞直到锁释放var mt sync.Mutex//银行卡取钱wg.Add(1)go func() {//拿到互斥锁mt.Lock()//加锁的访问fmt.Println("取钱前:",account.money)account.money -= 500time.Sleep(time.Nanosecond)fmt.Println("取钱后:",account.money)wg.Done()//释放互斥锁mt.Unlock()}()//存折存钱wg.Add(1)go func() {//拿到互斥锁(如果别人先抢到,则阻塞等待)mt.Lock()fmt.Println("存钱前:",account.money)account.money += 500time.Sleep(time.Nanosecond)fmt.Println("存钱后:",account.money)wg.Done()//释放互斥锁mt.Unlock()}()wg.Wait()
}

互斥锁案例2

  • 在上面的例子中,银行卡和存折的存取操作,必须强制同步,否则会形成数据的脏读或幻读;
  • 但如果是查询上个月的银行流水或者仅仅是查询用户名之类的只读操作,则没有强制同步的必要,完全可以并发执行;
  • 于是我们对上面的例子稍作修改,使得对银行账户的强制同步仅限于存取操作,而对于其他操作则放开权限令其可以被并发地执行;
  • 原理很简单:没有必要强制同步的任务,不去抢互斥锁就是了——需要确保同步的任务就先抢锁后执行,其余的则不去抢锁,直接执行;
package mainimport ("sync""fmt""time"
)//必须保证并发安全的数据
type Account struct {name  stringmoney float32//定义该数据的互斥锁mt    sync.Mutex
}//本方法不能被并发执行——并发安全的
func (a *Account) saveGet(amount float32) {//先将资源锁起来a.mt.Lock()//执行操作fmt.Println("操作前:", a.money)a.money += amountfmt.Println("操作后:", a.money)<-time.After(3 * time.Second)//释放资源a.mt.Unlock()
}//本方法可以被并发执行——不是并发安全的,无此必要
func (a *Account) getName() string {return a.name
}func main() {a := Account{name: "张全蛋", money: 1000}var wg sync.WaitGroupwg.Add(1)go func() {//调用一个加锁的方法(同步)a.saveGet(500)wg.Done()}()wg.Add(1)go func() {//调用一个加锁的方法(同步)a.saveGet(-500)wg.Done()}()for i:=0;i<3 ;i++  {wg.Add(1)go func() {//调用一个普通的没有访问锁的方法(异步)fmt.Println(a.getName())wg.Done()}()}wg.Wait()
}

通过信号量控制并发数

  • 控制并发数属于常用的调度;
  • 我们的做法是:规定并发执行的任务都必须先在某个监视管道中进行注册,而这个监视管道的缓存能力是固定的,比如说5,那么注册在该管道中的并发能力就是5;
package mainimport ("fmt""time""sync"
)/*信号量:通过控制管道的“带宽”(缓存能力)控制并发数*/func main() {//定义信号量为5“带宽”的管道sema = make(chan int, 5)var wg sync.WaitGroupfor i := 0; i < 100; i++ {wg.Add(1)go func(index int) {ret := getPingfangshu(index)fmt.Println(index, ret)wg.Done()}(i)}wg.Wait()
}//该函数只允许5并发执行
var sema chan int
func getPingfangshu(i int) int {sema <- 1<-time.After(2 * time.Second)<- semareturn i
}

区块链名师公开课QQ群:591229276
挑战20+月薪,加入【链界之巅的男人们】微信号:13924169175

学院Go语言视频主页
https://edu.csdn.net/lecturer/1928

清华团队带你实战区块链开发
扫码获取海量视频及源码 QQ群:721929980

并发技术4:同步调度相关推荐

  1. 4.5 并发技术:同步调度

    等待组 在此之前,我们让主协程等待子协程结束的方式都是睡眠,睡足子协程需要的时间,这种方式显然是不理想的! 等待组(sync.WaitGroup)的原理是:每增加一个子协程,就向等待组中+1,每结束一 ...

  2. 4.12 并发技术:sync包同步调度综合案例

    同步调度概述 Go语言的并发中,当使用go关键字开辟若干新的协程时,如果不加干涉,它们会完全并发地得到执行: 而所谓调度,就是在并发的局部植入一些串行和同步的操作,让某些协程有逻辑上的先后关系: 执行 ...

  3. 如何才能够系统地学习Java并发技术?

    Java并发编程一直是Java程序员必须懂但又是很难懂的技术内容. 这里不仅仅是指使用简单的多线程编程,或者使用juc的某个类.当然这些都是并发编程的基本知识,除了使用这些工具以外,Java并发编程中 ...

  4. Java并发技术学习总结

    Java并发 这篇总结主要是基于我Java并发技术系列的文章而形成的的.主要是把重要的知识点用自己的话说了一遍,可能会有一些错误,还望见谅和指点.谢谢 #更多详细内容可以查看我的专栏文章:Java并发 ...

  5. Java多线程并发技术

    Java多线程并发技术 参考文献: http://blog.csdn.net/aboy123/article/details/38307539 http://blog.csdn.net/ghsau/a ...

  6. 大型网站技术架构:核心原理与案例分析 mobi_阿里面试官:你会高并发技术吗?...

    前言 据有关数据统计,无论是游戏行业还是互联网行业,无论是软件开发公司还是大型网站,都对高并发技术人才有着巨大的需求.因此,无论为了是面试还是为了工作,学习高并发技术刻不容缓. 当然,高并发相关岗位的 ...

  7. python 线程同步_Python并发编程-线程同步(线程安全)

    Python并发编程-线程同步(线程安全) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 线程同步,线程间协调,通过某种技术,让一个线程访问某些数据时,其它线程不能访问这些数据,直 ...

  8. 深入理解高并发技术dpdk无锁队列

    前两周给大家直播分享,并发技术全景(从硬件,操作系统,虚拟机/标准库,编程语言等) 上半场(5个小时):并发/并行技术全景指南 下半场(5个小时):人生的下半场,你准备好了吗 最后我上周还布置了一个作 ...

  9. 即时通讯源码-即时通讯集群服务免费-通讯百万并发技术-Openfire 的安装配置教程手册-哇谷即时通讯集群方案-哇谷云-哇谷即时通讯源码

    即时通讯源码-即时通讯集群服务免费-通讯百万并发技术-Openfire 的安装配置教程手册-哇谷即时通讯集群方案-哇谷云 1,openfire开发环境配置 很久没有写点东西了.最近很烦心,领导不给力. ...

最新文章

  1. 系统权限管理设计 (转:http://blog.csdn.net/chexlong/article/details/37697555)
  2. html 如何实现一条竖线边上有 刻度_如何用低技术实现高性能
  3. Python档案袋( Sys 与 Import 模块)
  4. [20180428]DNS与ORA-12154错误.txt
  5. tomcat Server.xml Context配置
  6. 数据库事务(Database Transaction)
  7. 聊天机器人-AIML人工智能标记语言
  8. codeforces C. Valera and Tubes
  9. pip3 安装pycrypto 时报错
  10. 安装apache 后,找不到服务,解决办法
  11. Quartz的简单使用
  12. 将netcat-openbsd替换成为netcat-traditional
  13. scala implicit隐式转化与隐式参数
  14. Linux学习之Linux系统目录简概
  15. 计算机技术作文500字初一,初一关于那一刻的作文500字(精选10篇)
  16. 什么是超级立方体,HyperCube
  17. 销售书籍_我们的5合1图书销售又来了!
  18. 第十三周练兵区——编程题——不计入总分
  19. # 20155327 2016-2017-4 《Java程序设计》第七周学习总结
  20. NeurIPS 会议怎么读

热门文章

  1. 孙溟㠭篆刻《药生尘》——纪念吴孟超院士精神永在
  2. 2021年秋招遇到的前端笔试/面试题
  3. Testing the mettle
  4. linux下find、grep命令详解
  5. 蚂蚁全媒体中心刘鑫炜解答:企业网站推广的方法有哪些,附推广方案
  6. sqlserver根据字段查表_查找sqlserver数据库中,查询某值所表名和字段名
  7. 【图像处理】高效斑点特征提取技术研究(Matlab代码实现)
  8. Java基础(数组)数组扩容
  9. json解析数组 nlohmann_nlohmann/json 的主要用法
  10. 世界上第一根光纤,是谁造出来的?