Jquery中文网 www.jquerycn.cn
Jquery中文网 >  后端编程  >  Go语言  >  正文 Golang线程安全Map:sync.Map使用小结

Golang线程安全Map:sync.Map使用小结

发布时间:2021-05-06   编辑:www.jquerycn.cn
jquery中文网为您提供Golang线程安全Map:sync.Map使用小结等资源,欢迎您收藏本站,我们将为您提供最新的Golang线程安全Map:sync.Map使用小结资源

转载自:

https://blog.csdn.net/u010230794/article/details/82143179

https://www.jianshu.com/p/10a998089486

sync.Map的使用:

package main
import (
	"sync"
	"fmt"
)

func main() {
	//开箱即用
	var sm sync.Map
	//store 方法,添加元素
	sm.Store(1,"a")
	//Load 方法,获得value
	if v,ok:=sm.Load(1);ok{
		fmt.Println(v)
	}
	//LoadOrStore方法,获取或者保存
	//参数是一对key:value,如果该key存在且没有被标记删除则返回原先的value(不更新)和true;不存在则store,返回该value 和false
	if vv,ok:=sm.LoadOrStore(1,"c");ok{
		fmt.Println(vv)
	}
	if vv,ok:=sm.LoadOrStore(2,"c");!ok{
		fmt.Println(vv)
	}
	//遍历该map,参数是个函数,该函数参的两个参数是遍历获得的key和value,返回一个bool值,当返回false时,遍历立刻结束。
	sm.Range(func(k,v interface{})bool{
		fmt.Print(k)
		fmt.Print(":")
		fmt.Print(v)
		fmt.Println()
		return true
	})
}

利用传统的sync.RWMutex Map 实现并发安全的map:

var rwmap = struct{
		sync.RWMutex
		m map[string]string
	}{m: make(map[string]sring)}

读数据时候,读锁锁定:

rwmap.RLock()
value:= rwmap.m["key"]
rwmap.RUnlock()
fmt.Println("key:", value)

写数据的时候,写锁锁定:

rwmap.Lock()
rwmap.m["key"]="value"
rwmap.Unlock()

下面是有人做的两种map性能对比图:

可见随着cpu核心数的增加、并发加剧,这种读写锁 map的方式性能在不停的衰减,并且在核数为4的时候出现了性能的拐点;而sync.Map虽然性能不是特别好,但是相对比较平稳。

使用场景:

在服务器中,假设有一个存放用户信息的Map,在对这个Map进行操作时(如加入某个用户信息或去除某个用户信息),多协程对数据进行修改可能会导致数据竞争,因此需要使用线程安全的Map,如果使用普通Map的话会引起panic:

package main

func readMap(Map map[int]int, key int) int {
	return Map[key]
}

func writeMap(Map map[int]int, key int, value int) {
	Map[key] = value
}

func main()  {
	Map := make(map[int]int)

	for i := 0; i < 100000; i   {
		go writeMap(Map, i, i)
		go readMap(Map, i)
	}


}

go官方博客有如下说明:

Maps are not safe for concurrent use: it's not defined what happens when you read and write to them simultaneously. If you need to read from and write to a map from concurrently executing goroutines, the accesses must be mediated by some kind of synchronization mechanism. One common way to protect maps is with sync.RWMutex.

go FQA解释如下:

After long discussion it was decided that the typical use of maps did not require safe access from multiple goroutines, and in those cases where it did, the map was probably part of some larger data structure or computation that was already synchronized. Therefore requiring that all map operations grab a mutex would slow down most programs and add safety to few. This was not an easy decision, however, since it means uncontrolled map access can crash the program.

大致意思就是说,并发访问map是不安全的,会出现未定义行为,导致程序退出。所以如果希望在多协程中并发访问map,必须提供某种同步机制,一般情况下通过读写锁sync.RWMutex实现对map的并发访问控制,将map和sync.RWMutex封装一下,可以实现对map的安全并发访问,示例代码如下:

package main

import "sync"

type SafeMap struct {
	sync.RWMutex
	Map map[int]int
}

func newSafeMap(size int) *SafeMap {
	sm := new(SafeMap)
	sm.Map = make(map[int]int)
	return sm
}

func (sm *SafeMap) readMap(key int) int {
	sm.RLock()
	value := sm.Map[key]
	sm.RUnlock()
	return value
}

func (sm *SafeMap) writeMap(key int, value int) {
	sm.Lock()
	sm.Map[key] = value
	sm.Unlock()
}

func main()  {
	safeMap := newSafeMap(10)

	for i := 0; i < 100000; i   {
		go safeMap.writeMap(i, i)
		go safeMap.readMap(i)
	}
}

 

到此这篇关于“Golang线程安全Map:sync.Map使用小结”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Golang线程安全Map:sync.Map使用小结
golang runtime 简析
golang会取代php吗
如何在golang中关闭bufio.reader_golang 并发编程
「golang系列」浅谈Go语言
PHP线程安全和非线程安全版本的区别
php不支持多线程怎么办
关于Golang的介绍
golang 常见面试基础(1)
Go 语言学习路线指南

[关闭]