范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Go语言核心36讲(Go语言实战与应用十二)学习笔记

  34 | 并发安全字典sync.Map (上)
  我们今天再来讲一个并发安全的高级数据结构:sync.Map。众所周知,Go 语言自带的字典类型map并不是并发安全的。 前导知识:并发安全字典诞生史
  换句话说,在同一时间段内,让不同 goroutine 中的代码,对同一个字典进行读写操作是不安全的。字典值本身可能会因这些操作而产生混乱,相关的程序也可能会因此发生不可预知的问题。
  在sync.Map出现之前,我们如果要实现并发安全的字典,就只能自行构建。不过,这其实也不是什么麻烦事,使用 sync.Mutex或sync.RWMutex,再加上原生的map就可以轻松地做到。
  GitHub 网站上已经有很多库提供了类似的数据结构。我在《Go 并发编程实战》的第 2 版中也提供了一个比较完整的并发安全字典的实现。它的性能比同类的数据结构还要好一些,因为它在很大程度上有效地避免了对锁的依赖。
  尽管已经有了不少的参考实现,Go 语言爱好者们还是希望 Go 语言官方能够发布一个标准的并发安全字典。
  经过大家多年的建议和吐槽,Go 语言官方终于在 2017 年发布的 Go 1.9 中,正式加入了并发安全的字典类型sync.Map。
  这个字典类型提供了一些常用的键值存取操作方法,并保证了这些操作的并发安全。同时,它的存、取、删等操作都可以基本保证在常数时间内执行完毕。换句话说,它们的算法复杂度与map类型一样都是O(1)的。
  在有些时候,与单纯使用原生map和互斥锁的方案相比,使用sync.Map可以显著地减少锁的争用。sync.Map本身虽然也用到了锁,但是,它其实在尽可能地避免使用锁。
  我们都知道,使用锁就意味着要把一些并发的操作强制串行化。这往往会降低程序的性能,尤其是在计算机拥有多个 CPU 核心的情况下。
  因此,我们常说,能用原子操作就不要用锁,不过这很有局限性,毕竟原子只能对一些基本的数据类型提供支持。
  无论在何种场景下使用sync.Map,我们都需要注意,与原生map明显不同,它只是 Go 语言标准库中的一员,而不是语言层面的东西。也正因为这一点,Go 语言的编译器并不会对它的键和值,进行特殊的类型检查。
  如果你看过sync.Map的文档或者实际使用过它,那么就一定会知道,它所有的方法涉及的键和值的类型都是interface{},也就是空接口,这意味着可以包罗万象。所以,我们必须在程序中自行保证它的键类型和值类型的正确性。
  好了,现在第一个问题来了。 今天的问题是:并发安全字典对键的类型有要求吗?
  这道题的典型回答是:有要求。键的实际类型不能是函数类型、字典类型和切片类型。
  解析一下这个问题。  我们都知道,Go 语言的原生字典的键类型不能是函数类型、字典类型和切片类型。
  由于并发安全字典内部使用的存储介质正是原生字典,又因为它使用的原生字典键类型也是可以包罗万象的interface{};所以,我们绝对不能带着任何实际类型为函数类型、字典类型或切片类型的键值去操作并发安全字典。
  由于这些键值的实际类型只有在程序运行期间才能够确定,所以 Go 语言编译器是无法在编译期对它们进行检查的,不正确的键值实际类型肯定会引发 panic。
  因此,我们在这里首先要做的一件事就是:一定不要违反上述规则。我们应该在每次操作并发安全字典的时候,都去显式地检查键值的实际类型。无论是存、取还是删,都应该如此。
  当然,更好的做法是,把针对同一个并发安全字典的这几种操作都集中起来,然后统一地编写检查代码。除此之外,把并发安全字典封装在一个结构体类型中,往往是一个很好的选择。
  总之,我们必须保证键的类型是可比较的(或者说可判等的)。如果你实在拿不准,那么可以先通过调用reflect.TypeOf函数得到一个键值对应的反射类型值(即:reflect.Type类型的值),然后再调用这个值的Comparable方法,得到确切的判断结果。 知识扩展问题 1:怎样保证并发安全字典中的键和值的类型正确性?(方案一)
  简单地说,可以使用类型断言表达式或者反射操作来保证它们的类型正确性。
  为了进一步明确并发安全字典中键值的实际类型,这里大致有两种方案可选。
  第一种方案是,让并发安全字典只能存储某个特定类型的键。
  比如,指定这里的键只能是int类型的,或者只能是字符串,又或是某类结构体。一旦完全确定了键的类型,你就可以在进行存、取、删操作的时候,使用类型断言表达式去对键的类型做检查了。
  一般情况下,这种检查并不繁琐。而且,你要是把并发安全字典封装在一个结构体类型里面,那就更加方便了。你这时完全可以让 Go 语言编译器帮助你做类型检查。请看下面的代码: type IntStrMap struct {  m sync.Map }  func (iMap *IntStrMap) Delete(key int) {  iMap.m.Delete(key) }  func (iMap *IntStrMap) Load(key int) (value string, ok bool) {  v, ok := iMap.m.Load(key)  if v != nil {   value = v.(string)  }  return }  func (iMap *IntStrMap) LoadOrStore(key int, value string) (actual string, loaded bool) {  a, loaded := iMap.m.LoadOrStore(key, value)  actual = a.(string)  return }  func (iMap *IntStrMap) Range(f func(key int, value string) bool) {  f1 := func(key, value interface{}) bool {   return f(key.(int), value.(string))  }  iMap.m.Range(f1) }  func (iMap *IntStrMap) Store(key int, value string) {  iMap.m.Store(key, value) }
  如上所示,我编写了一个名为IntStrMap的结构体类型,它代表了键类型为int、值类型为string的并发安全字典。在这个结构体类型中,只有一个sync.Map类型的字段m。并且,这个类型拥有的所有方法,都与sync.Map类型的方法非常类似。
  两者对应的方法名称完全一致,方法签名也非常相似,只不过,与键和值相关的那些参数和结果的类型不同而已。在IntStrMap类型的方法签名中,明确了键的类型为int,且值的类型为string。
  显然,这些方法在接受键和值的时候,就不用再做类型检查了。另外,这些方法在从m中取出键和值的时候,完全不用担心它们的类型会不正确,因为它的正确性在当初存入的时候,就已经由 Go 语言编译器保证了。
  稍微总结一下。第一种方案适用于我们可以完全确定键和值的具体类型的情况。在这种情况下,我们可以利用 Go 语言编译器去做类型检查,并用类型断言表达式作为辅助,就像IntStrMap那样。 总结
  我们今天讨论的是sync.Map类型,它是一种并发安全的字典。它提供了一些常用的键、值存取操作方法,并保证了这些操作的并发安全。同时,它还保证了存、取、删等操作的常数级执行时间。
  与原生的字典相同,并发安全字典对键的类型也是有要求的。它们同样不能是函数类型、字典类型和切片类型。
  另外,由于并发安全字典提供的方法涉及的键和值的类型都是interface{},所以我们在调用这些方法的时候,往往还需要对键和值的实际类型进行检查。
  这里大致有两个方案。我们今天主要提到了第一种方案,这是在编码时就完全确定键和值的类型,然后利用 Go 语言的编译器帮我们做检查。
  在下一次的文章中,我们会提到另外一种方案,并对比这两种方案的优劣。除此之外,我会继续探讨并发安全字典的相关问题。 package main  import ( 	"fmt" 	"sync" )  // ConcurrentMap 代表自制的简易并发安全字典。 type ConcurrentMap struct { 	m  map[interface{}]interface{} 	mu sync.RWMutex }  func NewConcurrentMap() *ConcurrentMap { 	return &ConcurrentMap{ 		m: make(map[interface{}]interface{}), 	} }  func (cMap *ConcurrentMap) Delete(key interface{}) { 	cMap.mu.Lock() 	defer cMap.mu.Unlock() 	delete(cMap.m, key) }  func (cMap *ConcurrentMap) Load(key interface{}) (value interface{}, ok bool) { 	cMap.mu.RLock() 	defer cMap.mu.RUnlock() 	value, ok = cMap.m[key] 	return }  func (cMap *ConcurrentMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) { 	cMap.mu.Lock() 	defer cMap.mu.Unlock() 	actual, loaded = cMap.m[key] 	if loaded { 		return 	} 	cMap.m[key] = value 	actual = value 	return }  func (cMap *ConcurrentMap) Range(f func(key, value interface{}) bool) { 	cMap.mu.RLock() 	defer cMap.mu.RUnlock() 	for k, v := range cMap.m { 		if !f(k, v) { 			break 		} 	} }  func (cMap *ConcurrentMap) Store(key, value interface{}) { 	cMap.mu.Lock() 	defer cMap.mu.Unlock() 	cMap.m[key] = value }  func main() { 	pairs := []struct { 		k int 		v string 	}{ 		{k: 1, v: "a"}, 		{k: 2, v: "b"}, 		{k: 3, v: "c"}, 		{k: 4, v: "d"}, 	}  	// 示例1。 	{ 		cMap := NewConcurrentMap() 		cMap.Store(pairs[0].k, pairs[0].v) 		cMap.Store(pairs[1].k, pairs[1].v) 		cMap.Store(pairs[2].k, pairs[2].v) 		fmt.Println("[Three pairs have been stored in the ConcurrentMap instance]")  		cMap.Range(func(key, value interface{}) bool { 			fmt.Printf("The result of an iteration in Range: %v, %v ", 				key, value) 			return true 		})  		k0 := pairs[0].k 		v0, ok := cMap.Load(k0) 		fmt.Printf("The result of Load: %v, %v (key: %v) ", 			v0, ok, k0)  		k3 := pairs[3].k 		v3, ok := cMap.Load(k3) 		fmt.Printf("The result of Load: %v, %v (key: %v) ", 			v3, ok, k3)  		k2, v2 := pairs[2].k, pairs[2].v 		actual2, loaded2 := cMap.LoadOrStore(k2, v2) 		fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v) ", 			actual2, loaded2, k2, v2) 		v3 = pairs[3].v 		actual3, loaded3 := cMap.LoadOrStore(k3, v3) 		fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v) ", 			actual3, loaded3, k3, v3)  		k1 := pairs[1].k 		cMap.Delete(k1) 		fmt.Printf("[The pair with the key of %v has been removed from the ConcurrentMap instance] ", 			k1) 		v1, ok := cMap.Load(k1) 		fmt.Printf("The result of Load: %v, %v (key: %v) ", 			v1, ok, k1) 		v1 = pairs[1].v 		actual1, loaded1 := cMap.LoadOrStore(k1, v1) 		fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v) ", 			actual1, loaded1, k1, v1)  		cMap.Range(func(key, value interface{}) bool { 			fmt.Printf("The result of an iteration in Range: %v, %v ", 				key, value) 			return true 		}) 	} 	fmt.Println()  	// 示例2。 	{ 		var sMap sync.Map 		sMap.Store(pairs[0].k, pairs[0].v) 		sMap.Store(pairs[1].k, pairs[1].v) 		sMap.Store(pairs[2].k, pairs[2].v) 		fmt.Println("[Three pairs have been stored in the sync.Map instance]")  		sMap.Range(func(key, value interface{}) bool { 			fmt.Printf("The result of an iteration in Range: %v, %v ", 				key, value) 			return true 		})  		k0 := pairs[0].k 		v0, ok := sMap.Load(k0) 		fmt.Printf("The result of Load: %v, %v (key: %v) ", 			v0, ok, k0)  		k3 := pairs[3].k 		v3, ok := sMap.Load(k3) 		fmt.Printf("The result of Load: %v, %v (key: %v) ", 			v3, ok, k3)  		k2, v2 := pairs[2].k, pairs[2].v 		actual2, loaded2 := sMap.LoadOrStore(k2, v2) 		fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v) ", 			actual2, loaded2, k2, v2) 		v3 = pairs[3].v 		actual3, loaded3 := sMap.LoadOrStore(k3, v3) 		fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v) ", 			actual3, loaded3, k3, v3)  		k1 := pairs[1].k 		sMap.Delete(k1) 		fmt.Printf("[The pair with the key of %v has been removed from the sync.Map instance] ", 			k1) 		v1, ok := sMap.Load(k1) 		fmt.Printf("The result of Load: %v, %v (key: %v) ", 			v1, ok, k1) 		v1 = pairs[1].v 		actual1, loaded1 := sMap.LoadOrStore(k1, v1) 		fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v) ", 			actual1, loaded1, k1, v1)  		sMap.Range(func(key, value interface{}) bool { 			fmt.Printf("The result of an iteration in Range: %v, %v ", 				key, value) 			return true 		}) 	}  } 笔记源码
  https://github.com/MingsonZheng/go-core-demo

vivoX80Pro终于等到了,配置拉满售价感人,让你挪不开眼在前段时间不少友商都推出全新一代的骁龙8Gen1高端旗舰,对此智能手机市场也随之进入了4nm芯片时代。可让人没想到的是今年的vivo确如此的沉得住气,就连老对手OPPO首款4nm旗您知道灯槽还有专用空调室内机吗?现在伴随着生活的水平的提升以及对品质的追求,我们开始最求房间吊顶设计安装灯槽的方案,那么设计灯槽就会避免不了冬天制热夏天制冷的需求影响。今天还是由我来带大家学习和解锁一台可以解决我安卓对标OIS有人买苹果手机,有人买红米手机,这两者在使用上有什么区别吗?首先说下系统吧,苹果让很多果粉难以割舍的应该就是独有的ois系统,红米毋庸置疑是安卓系统。ois系统最大的优势在于系统流数字科技企业服务金融运营智能财务智能客服智能巡检数字科技服务金融,基于四个维度对金融领域中的场景用户,产品和运营进行全面数字化,并以数字化服务的方式进行输出。运营方面,借助人工智能的自动化决策和处理能力,实现了认证筛选客服监控等日内瓦车展发布28款新能源车德系品牌爆发PK特斯拉2019年3月5日,日内瓦车展将正式开幕。网上车市经过梳理后发现,本届车展将发布80余款新车,其中新能源车型多达28款,占比超过30,包括奥迪etron新能源家族宝马iPerfor传微软正在开发轻量化的WindowsLite系统为双屏设备而设Android曾推出轻量版的Androidlite,而现在Microsoft似乎也打算搞一个轻量版的Windows系统,其定位会与ChromeOS接近,除了是个轻量化的系统以外,似途牛2018年Q4市场份额28。63实现全年NonGAAP盈利中新网3月5日电3月4日,Analysys易观发布的中国在线度假旅游市场季度监测分析2018年第4季度显示,2018年第4季度,中国在线度假旅游市场交易规模达到225。12亿元,同建市40年成世界一线城深圳创造城市发展奇迹上面4张图,分别是上世纪80年代深圳中心城区2001年中心城区2008年中心城区2019年中心城区。40年,深圳发生了翻天覆地的变化。鲁力摄(翻拍)2月21日,空客(中国)创新中心100年前泰坦尼克ampquot号邮轮螺旋桨上的一个有趣的问题最近在看100年前泰坦尼克号邮轮高清图片时,无意中发现了螺旋桨上一个有趣的问题,特意分享给大家。泰坦尼克号邮轮泰坦尼克号邮轮于1909年3月31日在北爱尔兰贝尔法斯特港的哈兰德与沃中国崛起利器!工业互联网八大行业深度解析智东西内参(公众号zhidxcom)2017年以来,工业互联网应用范围和深度不断扩展,场景已覆盖产品资产生产线商业企业间等全要素全价值链和全产业链,企业加速大规模实施的工业互联网项风起了!SAPOdoo国际巨头逐鹿中小企业ERP风起了!SAPOdoo国际巨头逐鹿中小企业ERP作者刘学习1月31日,深耕大中型企业ERP市场的SAP发布了中国加速计划,深耕中小企业市场,打造新型生态系统。SAP全球执行副总裁大
iPhone14Pro配置曝光比低配机型强太多,苹果再秀精准刀法骁龙8手机越来越多,但丝毫没影响到苹果的生意,凭借着性能出色的A15芯片和iOS生态,十三香iPhone13系列依旧在热销中。根据爆料,苹果新款手机iPhoneSE3将于3月8日前千元内无法避开,大推力也能享纯净之声,乂度音频小尾巴Link2Bal入坑的方式有许多种,有人因颜值也有人因性能,也有对于硬件党的固执。在这个无线轻量化时代的大背景下,音频小尾巴的风靡程度明显要高于国砖。正是由于价格和功能性的优势,可以让不少有线Hi联想4K显示器上架采用31。5英寸IPS超清巨幕屏近日,联想在电商平台上架一款全新31。5英寸4K显示器L32p30,支持TypeC一线传输供电,目前,联想L32p30显示器已开启预售,将于2月24日正式开售,首发价1999元,感即开即热澎湃热水分秒必达海尔双增压零冷水燃气热水器评测众所周知,在魔都只有两个季节冬天和夏天,所以即便现在已经过了正月十五,春节假期也正式结束,魔都仍没有一丝丝回暖的意思,甚至还在不断试探降温的底线。可是,生活还要继续,我们也依旧在为在人像摄影中,相机有哪些重要的拍摄功能设置?人像摄影可谓摄影题材中的核心类别,也是小k非常喜爱拍摄的一类题材。人像摄影又细分不同类别,但一些主要拍摄参数的设置基本是通用的。谈一谈个人在人像摄影参数设置上的一些经验和体会,仅供会声会影2022重磅发布!会声会影2022全新功能详解会声会影是一款简单实用的视频编辑软件,深受用户的喜爱和欢迎。随着新的一年开启,会声会影也即将推出2022版,不知道这次它会为我们准备什么惊喜呢?做好准备,下面就为大家介绍会声会影2微信怎么开通数字人民币微信开通数字人民币功能操作方法微信怎么开通数字人民币?其实这个问题还是很多人都不清楚的。近期,数字人民币客户端已经上架至各大应用商店,而腾讯目前已接入数字人民币,而且腾讯开始为用户提供数字人民币服务。那么我们怎移动自带的光猫带无线路由功能,用不用关掉,用光猫的路由拨号还是自备的路由器拨号?带无线路由功能的光猫虽然可以使用,但是网络信号肯定不如外加独立路由器效果好,如果对网络带宽需求量大的,我建议关闭光猫路由功能,光猫只当交换机使用,外加路由器分配网络资源,具体配置是白手起家171为什么线上的企业纷纷冲到线下开店?互联网的人口红利已经到天花板了,存量市场里面竞争越来越激烈了,要想在线上实现增长越来越难,所以就把增长的突破口放在了线下。线上的流量转化越来越贵,而通过线下门店获取新用户,透过店里钉钉飞书企业微信,谁才是最后的赢家?新眸企业服务组作品作者阮雪编辑桑明强在OA还未内嵌至办公自动化时,协同办公一度被认为是未来。但疫情黑天鹅倒逼办公地点从线下转移到线上后,脱离了原来办公室提供的工作场景,每个人都成了小米10S提升音质音效大家的小米10S是不是升级最新的13后,是不是感觉音质音效不如12,或者之前版本,低音全无了,我是手动更新一下手机的音质,大家也是13系统的10s手机,可以找一下音质包,我把我个人