Golang从入门到放弃200618--Map(3)Map的并发

本文深入讨论了Golang中Map的并发问题,指出原生Map不支持并发读写,并强调Key必须是可比较类型。文章提到了并发操作可能导致的性能瓶颈,并分析了两种并发控制策略的优缺点:官方的读写分离方案以及在Map中加锁。同时,提出了通过降低锁粒度以优化并发性能的思路,并给出了测试Map并发的面试题。
  • 参考资料
    由浅入深聊聊Golang的map
    Go夜读关于Map的资料

  • Map的知识点

    • Map是无序的,所以每次遍历的顺序随机
    • 原生的Map不支持并发读写
    • Map中 Key 必须要是被比较类型 Value 可以是任意类型
      不可被比较的 : slice、map 、 func
    • Map的底层结构是HSMap
  • Map的并发操作

    • 测试Map是否并发
    	func main() {
    		test := map[int]string{1: "test"}
    		go func() {
    			for {
    				test[1] = "test"
    			}
    		}()
    
    		go func() {
    			for {
    				test[1] = "test"
    			}
    		}()
    		for {
    
    		}
    		fmt.Println(test)
    	}
    

    返回数据:

    fatal error: concurrent map writes
    
    • 解决方案1 : Map中加锁
    	var s sync.RWMutex
    	var Test = map[int]string{1: "test"}
    	func main() {
    		for i := 0; i < 50; i++ {
    			go test()
    		}
    		time.Sleep(5 * time.Second)
    	}
    
    	func test() {
    		// var s sync.RWMutex
    		// 锁加载函数里面会出现下面的错误
    		// fatal error: concurrent map iteration and map write
    		
    		go func() {
    			for {
    				s.Lock()
    				Test[1] = "test1"
    				s.Unlock()
    			}
    		}()
    
    		go func() {
    			for {
    				s.Lock()
    				Test[1] = "test2"
    				s.Unlock()
    			}
    		}()
    		time.Sleep(time.Second)
    		fmt.Printf("%v %p\n", test, test)
    	}
    

    返回数据

    	map[1:test1]
    	map[1:test2]随机出现			
    

    优点: 实现简单粗暴,好理解
    缺点: 锁的粒度为整个Map,存在优化的空间
    适用场景: all

    • 解决方案2 :
    var s sync.Map
    func main() {
    	s.Store(1, 1)
    	for i := 0; i < 50; i++ {
    		go test()
    	}
    	time.Sleep(5 * time.Second)
    }
    
    func test() {
    	go func() {
    		for {
    			s.Store(1, 2)
    		}
    	}()
    
    	go func() {
    		for {
    			s.Store(1, 3)
    		}
    	}()
    	time.Sleep(time.Second)
    	fmt.Println(s.Load(1))
    }		
    

    返回结果:

    2 true
    3 true
    

    优点:官方出品;空间换时间;读写分离
    缺点:不适用大量写的场景,这样会导致read Map读不到数据,而进一步加
    锁读取,同时dirty Map也会一直晋升为read Map,整体性较差
    适用场景: 大量读,少量写

    优化方向: 把锁的粒度尽可能降低来提高运行速度
    实现

  • 面试题

    【中级】关于map,下面说法正确的是()
    A. map反序列化时json.unmarshal的入参必须为map的地址
    B. 在函数调用中传递map,则子函数中对map元素的增加不会导致父函数中map的修改
    C. 在函数调用中传递map,则子函数中对map元素的修改不会导致父函数中map的修改
    D. 不能使用内置函数delete删除map的元素
    
    参考答案:A
    
    【初级】使用map不需要引入任何库()
    
    参考答案:T
    
    
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值