Go并发编程指南第一篇
竞争条件和数据竞争
当两个或多个操作必须以正确的顺序执行时,就会出现竞争条件,但程序尚未编写为保证维护此顺序。
数据竞争是指一个并发操作试图读取一个变量,而在某个不确定的时间另一个并发操作试图写入同一个变量。main func 是主 goroutine。 func main() { var data int go func() { data++ }() if data == 0 { fmt.Printf("the value is %d", data) } }sync内存访问同步
sync 包包含对低级内存访问同步最有用的并发原语。临界区是代码中可以访问共享内存的地方mutex互斥体
Mutex 代表"互斥",是一种保护程序关键部分的方法。 type Counter struct { mu sync.Mutex value int } func (c *Counter) Increment() { c.mu.Lock() defer c.mu.Unlock() c.value++ }waitgroup等待组
调用添加一组goroutines var wg sync.WaitGroup for _, salutation := range []string{"hello", "greetings", "good day"} { wg.Add(1) go func(salutation string) { defer wg.Done() fmt.Println(salutation) }(salutation) } wg.Wait()读写互斥锁
更细粒度的内存控制,可以请求只读锁 producer := func(wg *sync.WaitGroup, l sync.Locker) { defer wg.Done() for i := 5; i > 0; i-- { l.Lock() l.Unlock() time.Sleep(1) } } observer := func(wg *sync.WaitGroup, l sync.Locker) { defer wg.Done() l.Lock() defer l.Unlock() } test := func(count int, mutex, rwMutex sync.Locker) time.Duration { var wg sync.WaitGroup wg.Add(count+1) beginTestTime := time.Now() go producer(&wg, mutex) for i := count; i > 0; i-- { go observer(&wg, rwMutex) } wg.Wait() return time.Since(beginTestTime) } tw := tabwriter.NewWriter(os.Stdout, 0, 1, 2, " ", 0) defer tw.Flush() var m sync.RWMutex fmt.Fprintf(tw, "Readers RWMutex Mutex ") for i := 0; i < 20; i++ { count := int(math.Pow(2, float64(i))) fmt.Fprintf( tw, "%d %v %v ", count, test(count, &m, m.RLocker()), test(count, &m, &m), ) }cond条件
如果有某种方法可以让 goroutine 有效地休眠,直到收到唤醒并检查其状态的信号,那就更好了。这正是 Cond 类型为我们所做的。
Cond 和 Broadcast 是用于通知在 Wait 调用中阻塞的 goroutines 条件已被触发的方法。 type Button struct { Clicked *sync.Cond } func main() { button := Button{ Clicked: sync.NewCond(&sync.Mutex{}), } // running on goroutine every function that passed/registered // and wait, not exit until that goroutine is confirmed to be running subscribe := func(c *sync.Cond, param string, fn func(s string)) { var goroutineRunning sync.WaitGroup goroutineRunning.Add(1) go func(p string) { goroutineRunning.Done() c.L.Lock() // critical section defer c.L.Unlock() fmt.Println("Registered and wait ... ") c.Wait() fn(p) }(param) goroutineRunning.Wait() } var clickRegistered sync.WaitGroup for _, v := range []string{ "Maximizing window.", "Displaying annoying dialog box!", "Mouse clicked."} { clickRegistered.Add(1) subscribe(button.Clicked, v, func(s string) { fmt.Println(s) clickRegistered.Done() }) } button.Clicked.Broadcast() clickRegistered.Wait() }Once
确保即使在多个 goroutine 之间也只执行一次 var count int increment := func() { count++ } var once sync.Once var increments sync.WaitGroup increments.Add(100) for i := 0; i < 100; i++ { go func() { defer increments.Done() once.Do(increment) }() } increments.Wait() fmt.Printf("Count is %d ", count)Pool
管理连接池,数量 package main import ( "fmt" "sync" ) func main() { myPool := &sync.Pool{ New: func() interface{} { fmt.Println("Creating new instance.") return struct{}{} }, } // Get call New function defined in pool if there is no instance started myPool.Get() instance := myPool.Get() fmt.Println("instance", instance) // here we put a previously retrieved instance back into the pool, // this increases the number of instances available to one myPool.Put(instance) // when this call is executed, we will reuse the // previously allocated instance and put it back in the pool myPool.Get() var numCalcsCreated int calcPool := &sync.Pool{ New: func() interface{} { fmt.Println("new calc pool") numCalcsCreated += 1 mem := make([]byte, 1024) return &mem }, } fmt.Println("calcPool.New", calcPool.New()) calcPool.Put(calcPool.New()) calcPool.Put(calcPool.New()) calcPool.Put(calcPool.New()) calcPool.Put(calcPool.New()) calcPool.Get() const numWorkers = 1024 * 1024 var wg sync.WaitGroup wg.Add(numWorkers) for i := numWorkers; i > 0; i-- { go func() { defer wg.Done() mem := calcPool.Get().(*[]byte) defer calcPool.Put(mem) // Assume something interesting, but quick is being done with // this memory. }() } wg.Wait() fmt.Printf("%d calculators were created.", numCalcsCreated) }死锁
死锁是其中所有并发进程都在等待彼此。 package main import ( "fmt" "sync" "time" ) type value struct { mu sync.Mutex value int } func main() { var wg sync.WaitGroup printSum := func(v1, v2 *value) { defer wg.Done() v1.mu.Lock() defer v1.mu.Unlock() // deadlock time.Sleep(2 * time.Second) v2.mu.Lock() defer v2.mu.Unlock() fmt.Printf("sum=%v ", v1.value+v2.value) } var a, b value wg.Add(2) go printSum(&a, &b) go printSum(&b, &a) wg.Wait() }
总结
本文是go语言并发编程指南最佳实践第一篇,后续第二篇还会整理各种channel的特性,锁的使用在并发编程中的特点与各种用途举例,全部都是最接地气的代码示例。关注我,敬请期待下一篇。
曾繁华的古镇变得无人去,门票上涨遭游客嫌弃,商家纷纷摇了摇头近几年来,古镇旅游在我国火遍大江南北。许多各种仿古的小镇,没有文化的底蕴以及千篇一律的建筑和商业混搭模式,让许多旅游古镇变得不伦不类,让人们失去了对古镇的兴趣,游客没有了想去的意愿
消息称荣耀80还有直屏版,Magic5系列再曝近日,荣耀MagicVs荣耀80系列新品发布会正式到来。全新的荣耀80系列手机亮相发布,提供荣耀80荣耀80Pro荣耀80SE三款新机。据悉,全新的荣耀80三款新机都采用了曲屏设计
广州市交通运输局最大限度把对市民出行的影响降到最低南方财经全媒体记者黄浩博广州报道11月28日,广州市举行疫情防控新闻发布会。广州市交通运输局副局长张孜介绍,受疫情影响,近两日广州涉疫的有关各区先后发布了临时管控通告,市民整体出行
如何理解不因水清而偏用,也只能不因水浊而偏废,自古皆然如何理解大明王朝1566嘉靖皇帝不因水清而偏用,也只能不因水浊而偏废,自古皆然这句话?这句话体现了嘉靖皇帝对朝廷政治生态的深刻洞悉和理解。这句话说的不仅特别有道理,而且而且特别有预
死后宁愿和猴子埋一块,善利用脸蛋的川岛芳子,临终看透世界1948年3月25日,北平的天气还是很寒冷,可是全城百姓的心却很温暖。因为这一天,危害国家无数次的大间谍川岛芳子要执行死刑,真是大快人心!死后,把我和猴子埋在一起!临刑前,由于长期
大明朝第一卧底,帮朱棣夺得江山,最终却险些被饿死藩王起兵谋反夺得天下,朱棣是古往今来第一人。朱棣能够成功的因素有很多,但是根本原因只有两个一个是朱棣的确很能打另一个是当时的朝廷,无论文臣还是武将实在是太菜了。这两个原因互为条件而
寒潮来势汹汹席卷我国中东部南方多地雨雪明显中国天气网讯今年下半年以来最强寒潮目前已经进入主要影响时段!今明两天(11月29日至30日),寒潮还将继续自北向南席卷我国中东部大部地区,各地气温将剧烈下滑。而南方地区则会在寒潮影
三亚有什么特色小吃?这些特色小吃,旅游时可边看海边品尝三亚旅游的特色小吃有抱罗粉,清补凉,崖城酸粉,椰子糖,椰子饭。港口粉,鸡屎藤汤圆,炸虾饼,疍家粽,三亚米花糖等。抱罗粉,当地人的特色面食。口味好,有干拌和汤捞两种,浇头可以自己选,
5G下井,让老矿焕新颜身处地下几十米甚至几百米的煤矿矿井内,发生紧急情况应该如何与地面联系?以前,矿工往往只能使用固定电话。如今,得益于5G等新技术的发展应用,井下与井上的实时通话得以实现。刘庄煤矿位于
富力找来了富朋友朋友多了路好走这句话用来形容富力再合适不过。从行业首批出险房企到如今境外债境内债双双打包展期成功,该公司在化债方面的进程不免令其它同类型企业艳羡。2020年以来,富力一直奔走在卖资
食品饮料行业年度策略否极泰来,景气复苏(报告出品方华泰证券)2022年基本面调整,估值回落,负重前行22Q13中信食品饮料板块实现营收扣非净利7524。51365。1亿元,同比1114,保持韧性增长,但增长速度有所回落
世界杯巴西VS韩国,内马尔复出,巴西轻松晋级淘汰赛?应各位粉丝的要求,今天先来跟大家聊聊巴西对韩国的淘汰赛看法。世界杯巴西VS韩国巴西虽然毫无压力的跻身淘汰赛,但看了这三场小组赛的朋友们,一定会为巴西的前景有所担心,头重脚轻的巴西真
钉钉会议也收费了!一年9800元,割韭菜是专业的第一观点网报道钉钉视频会议本来不是什么新鲜玩意,但是在口罩之乱的大环境下,反倒成了人们工作学习的主要工具了,打工人们每天开会都得用视频会议,学生党每天上网课也得用视频会议,真的可以
特斯拉拒不向中国妥协,丰田却称中国最重要,又添黑马表诚意作为漂亮国品牌,特斯拉和苹果一样,从一开始就是定位高端,所以售价颇贵,但即便如此,其销量也一直很高。面对中国用户,特斯拉格外有底气,无论消费者怎么投诉,它也不做改变,甚至放言决不向
岚图11月交付1508辆汽车(文潘昱辰编辑周远方)日前,岚图汽车公布今年11月交付数据。受诸多不利因素影响,11月岚图共交付新车1508辆,同比增长32。今年111月,岚图累计交付汽车17680辆,不过仅完成
真的强!这款谷歌插件,全网资源随便下网友千千万,车友占一半。最近好多小伙伴问有没有好的资源网站,小雷呢,也只能笑笑不语,之前分享了那么多,竟然还要问,一看就没做好功课。记得前段时间分享了一个资源搜索网站,可以整合各大
续航717km的零跑C01会是纯电轿车性价比之王吗?在油价飞涨日子,每次去加油站我都感觉到肉疼,所以想入手辆电动车想法越来越强烈。5月10日正式发布零跑C01勾起了我极兴趣,发布会共推出了5款车型,预售价为1827万元区间。零跑C0
你最关注的10个问题,我们替你问了ChatGPT擅长打太极,但也确实在认真回答。AIGC作画带给人们的惊艳感觉还没散去,ChatGPT又来刺激人类脆弱的神经了。当地时间11月30日,代替跳票的GPT4,OpenAI发布了新的对话
全国秋粮收购累计超七千万吨收购进度快于去年同期央广网北京12月6日消息据国家粮食和物资储备局消息,自秋粮上市以来,秋粮收购各项工作正在全面有序推进。加工企业积极补库,储备企业启动轮换,贸易企业看好后市,市场收购较为活跃,市场化
明日大雪,别管有钱没钱,这5样美食记得吃,御寒解馋营养足明天就是入冬以来的第三个节气大雪。每到大雪前后,大部分地区的最低温度都在零度以下,因此不少地区会出现降雪天气,寒邪更重。要格外注意头部和脚部的保暖,除了多添衣物,大雪期间的饮食状况
什么是好的技术技术的本质是提高效率,当效率提升到一定高度,就带来质变。从而形成对旧事物的降维打击。最近经历组织架构的调整,几千号程序员如同大雁一般,被CTO一会排成S形,一会排成B形。我作为一名
威马汽车再爆伤薪事为渡过寒冬,员工待遇节衣缩食要知道,曾经的威马汽车是造车新势力头部车企之一,更是与蔚来小鹏理想并称为造车四小龙,甚至还拿下了不少个率先的头衔。但是作为曾经造车新势力中有头有脸的威马,如今几乎却成了掉队的代名词