-
go sync.Map使用和介绍
2018-08-28 15:14:29sync.Map使用和介绍 首先看下该map的使用: _** package main import ( “sync” “fmt” ) func main() { //开箱即用 var sm sync.Map //store 方法,添加元素 sm.Store(1,”a”) //Load 方法,...sync.Map使用和介绍
1、首先看下该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 }) }
运行结果:
a a c 1:a 2:c
2、利用传统的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()
3、两种map的性能对比:
下面是有人做的两种map性能对比图:
可见随着cpu核心数的增加、并发加剧,这种读写锁+map的方式性能在不停的衰减,并且在核数为4的时候出现了性能的拐点;而sync.Map虽然性能不是特别好,但是相对比较平稳。
4、sync.Map 源码解析
源码位于:src\sync\map.go
首先查看一下sync.Map的数据结构:type Map struct { // 该锁用来保护dirty mu Mutex // 存读的数据,因为是atomic.value类型,只读类型,所以它的读是并发安全的 read atomic.Value // readOnly //包含最新的写入的数据,并且在写的时候,会把read 中未被删除的数据拷贝到该dirty中,因为是普通的map存在并发安全问题,需要用到上面的mu字段。 dirty map[interface{}]*entry // 从read读数据的时候,会将该字段+1,当等于len(dirty)的时候,会将dirty拷贝到read中(从而提升读的性能)。 misses int }
read的数据结构是:
type readOnly struct { m map[interface{}]*entry // 如果Map.dirty的数据和m 中的数据不一样是为true amended bool }
entry的数据结构:
type entry struct { //可见value是个指针类型,虽然read和dirty存在冗余情况(amended=false),但是由于是指针类型,存储的空间应该不是问题 p unsafe.Pointer // *interface{} }
Delete
首先来看delete方法func (m *Map) Delete(key interface{}) { read, _ := m.read.Load().(readOnly) e, ok := read.m[key] //如果read中没有,并且dirty中有新元素,那么就去dirty中去找 if !ok && read.amended { m.mu.Lock() //这是双检查(上面的if判断和锁不是一个原子性操作) read, _ = m.read.Load().(readOnly) e, ok = read.m[key] if !ok && read.amended { //直接删除 delete(m.dirty, key) } m.mu.Unlock() } if ok { //如果read中存在该key,则将该value 赋值nil(采用标记的方式删除!) e.delete() } } func (e *entry) delete() (hadValue bool) { for { p := atomic.LoadPointer(&e.p) if p == nil || p == expunged { return false } if atomic.CompareAndSwapPointer(&e.p, p, nil) { return true } } }
Store
新加元素func (m *Map) Store(key, value interface{}) { // 如果m.read存在这个key,并且没有被标记删除,则尝试更新。 read, _ := m.read.Load().(readOnly) if e, ok := read.m[key]; ok && e.tryStore(&value) { return } // 如果read不存在或者已经被标记删除 m.mu.Lock() read, _ = m.read.Load().(readOnly) if e, ok := read.m[key]; ok { //如果entry被标记expunge,则表明dirty没有key,可添加入dirty,并更新entry if e.unexpungeLocked() { //加入dirty中 m.dirty[key] = e } //更新value值 e.storeLocked(&value) //dirty 存在该key,更新 } else if e, ok := m.dirty[key]; ok { e.storeLocked(&value) //read 和dirty都没有,新添加一条 } else { //dirty中没有新的数据,往dirty中增加第一个新键 if !read.amended { //将read中未删除的数据加入到dirty中 m.dirtyLocked() m.read.Store(readOnly{m: read.m, amended: true}) } m.dirty[key] = newEntry(value) } m.mu.Unlock() } //将read中未删除的数据加入到dirty中 func (m *Map) dirtyLocked() { if m.dirty != nil { return } read, _ := m.read.Load().(readOnly) m.dirty = make(map[interface{}]*entry, len(read.m)) //read如果较大的话,可能影响性能 for k, e := range read.m { //通过此次操作,dirty中的元素都是未被删除的,可见expunge的元素不在dirty中 if !e.tryExpungeLocked() { m.dirty[k] = e } } } //判断entry是否被标记删除,并且将标记为nil的entry更新标记为expunge func (e *entry) tryExpungeLocked() (isExpunged bool) { p := atomic.LoadPointer(&e.p) for p == nil { // 将已经删除标记为nil的数据标记为expunged if atomic.CompareAndSwapPointer(&e.p, nil, expunged) { return true } p = atomic.LoadPointer(&e.p) } return p == expunged } //对entry 尝试更新 func (e *entry) tryStore(i *interface{}) bool { p := atomic.LoadPointer(&e.p) if p == expunged { return false } for { if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) { return true } p = atomic.LoadPointer(&e.p) if p == expunged { return false } } } //read里 将标记为expunge的更新为nil func (e *entry) unexpungeLocked() (wasExpunged bool) { return atomic.CompareAndSwapPointer(&e.p, expunged, nil) } //更新entry func (e *entry) storeLocked(i *interface{}) { atomic.StorePointer(&e.p, unsafe.Pointer(i)) }
可见,每次操作先检查read,因为read 并发安全,性能好些;read不满足,则加锁检查dirty,一旦是新的键值,dirty会被read更新。
Load
加载方法,查找key。func (m *Map) Load(key interface{}) (value interface{}, ok bool) { //因read只读,线程安全,先查看是否满足条件 read, _ := m.read.Load().(readOnly) e, ok := read.m[key] //如果read没有,并且dirty有新数据,那从dirty中查找,由于dirty是普通map,线程不安全,这个时候用到互斥锁了 if !ok && read.amended { m.mu.Lock() // 双重检查 read, _ = m.read.Load().(readOnly) e, ok = read.m[key] // 如果read中还是不存在,并且dirty中有新数据 if !ok && read.amended { e, ok = m.dirty[key] // mssLocked()函数是性能是sync.Map 性能得以保证的重要函数,目的讲有锁的dirty数据,替换到只读线程安全的read里 m.missLocked() } m.mu.Unlock() } if !ok { return nil, false } return e.load() } //dirty 提升至read 关键函数,当misses 经过多次因为load之后,大小等于len(dirty)时候,讲dirty替换到read里,以此达到性能提升。 func (m *Map) missLocked() { m.misses++ if m.misses < len(m.dirty) { return } //原子操作,耗时很小 m.read.Store(readOnly{m: m.dirty}) m.dirty = nil m.misses = 0 }
源码用的是1.9版本,通过阅读源码我们发现sync.Map是通过冗余的两个数据结构(read、dirty),实现性能的提升。为了提升性能,load、delete、store等操作尽量使用只读的read;为了提高read的key击中概率,采用动态调整,将dirty数据提升为read;对于数据的删除,采用延迟标记删除法,只有在提升dirty的时候才删除。
-
Map使用Iterator遍历输出
2016-07-26 22:31:03Map使用Iterator遍历输出java中的map有好几种输出方法,本篇博客只讲其中的迭代器输出
代码如下
import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class MapOutput { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Map<Integer,String> map = new HashMap<Integer,String>(); map.put(1, "aaa"); map.put(2, "bbb"); map.put(3, "ccc"); map.put(4, "ddd"); Iterator<Map.Entry<Integer,String>> it=map.entrySet().iterator(); while(it.hasNext()){ Map.Entry<Integer,String> entry=it.next(); System.out.println("key="+entry.getKey()+","+"value="+entry.getValue()); } } }
输出结果如下key=1,value=aaa
key=2,value=bbb
key=3,value=ccc
key=4,value=ddd -
map使用return false无法退出循环
2019-11-07 14:59:24map使用return false无法退出循环 解决方法: 使用for替换map,for可以使用return false退出循环map使用return false无法退出循环
解决方法:
使用for替换map,for可以使用return false退出循环
-
Scala中的Map使用例子
2016-12-27 22:09:46Map结构是一种非常常见的结构,在各种程序语言都有对应的api,由于Spark的底层语言是Scala,所以有必要来了解下Scala中的Map使用方法。 (1)不可变Map 特点: api不太丰富 如果是var修饰,引用可变,...Map结构是一种非常常见的结构,在各种程序语言都有对应的api,由于Spark的底层语言是Scala,所以有必要来了解下Scala中的Map使用方法。
(1)不可变Map
特点:
api不太丰富
如果是var修饰,引用可变,支持读写
如果是val修饰,引用不可变,只能写入一次值,其后只读
var a:Map[String,Int]=Map("k1"->1,"k2"->2)//初始化构造函数 a += ("k3"->3)//添加元素 a += ("k4"->4)//添加元素 a += ("k1"->100)//已经存在添加元素会覆盖 a -= ("k2","k1")//删除元素 // a("k1") = "foo"//不支持 println(a.contains("k6"))//是否包含某元素 println(a.size)//打印大小 println(a.get("k1").getOrElse("default")) //根据key读取元素,不存在就替换成默认值 a.foreach{case (e,i) => println(e,i)} //遍历打印1 for( (k,v)<-a ) println(k,v) //遍历打印2 println(a.isEmpty)//判断是否为空 a.keys.foreach(println)//只打印key a.values.foreach(println)//只打印value a=Map()//数据清空使用再次new println(a.size) a.toSeq.sortBy(_._1)//升序排序 key a.toSeq.sortBy(_._2)//升序排序 value a.toSeq.sortWith(_._1>_._1) //降序排序 key a.toSeq.sortWith(_._2>_._2) //降序排序 value //下面自定义按英文字母或数字排序 implicit val KeyOrdering=new Ordering[String] { override def compare(x: String, y: String): Int = { x.compareTo(y) } } println(a.toSeq.sorted)
(2)可变Map例子
特点:
api丰富与Java中Map基本类似
如果是var修饰,引用可变,支持读写
如果是val修饰,引用不可变,支持读写
def map3(): Unit ={ //不可变Map+var关键词修饰例子 var a:scala.collection.mutable.Map[String,Int]=scala.collection.mutable.Map("k1"->1,"k2"->2)//初始化构造函数 a += ("k3"->3)//添加元素 a += ("k4"->4)//添加元素 a += ("k1"->100)//已经存在添加元素会覆盖 a += ("k1"->100,"k9"->9)//添加多个元素 a -= ("k2","k1")//删除元素 a ++= List("CA" -> 23, "CO" -> 25)//追加集合 a --= List("AL", "AZ")//删除集合 a.retain((k,v)=> k=="k1")//只保留等于k1元素,其他的删除 a.put("put1",200)//put a.remove("k2")//remove a.clear()//清空 a("k3")=100//支持 println(a.contains("k6"))//是否包含某元素 println(a.size)//打印大小 println(a.get("k1").getOrElse("default")) //根据key读取元素,不存在就替换成默认值 a.foreach{case (e,i) => println(e,i)} //遍历打印1 for( (k,v)<-a ) println(k,v) //遍历打印2 println(a.isEmpty)//判断是否为空 a.keys.foreach(println)//只打印key a.values.foreach(println)//只打印value a=scala.collection.mutable.Map()//引用能变 println(a.size) a.toSeq.sortBy(_._1)//排序 key a.toSeq.sortBy(_._2)//排序 value a.toSeq.sortWith(_._1>_._1) //降序排序 key a.toSeq.sortWith(_._2>_._2) //降序排序 value //下面自定义按英文字母或数字排序 implicit val KeyOrdering=new Ordering[String] { override def compare(x: String, y: String): Int = { x.compareTo(y) } } println(a.toSeq.sorted) }
有什么问题可以扫码关注微信公众号:我是攻城师(woshigcs),在后台留言咨询。 技术债不能欠,健康债更不能欠, 求道之路,与君同行。
-
json对象作为map使用
2018-08-13 15:31:27json对象作为map使用 原理就是Json对象里还是放Json对象 可以 : var obj = {}; obj.id = info.id; //这里id是key 的名称 也可以: var obj = {}; obj["id"] = info.id; //这里id也是... -
Java中Map使用/渠道ID
2018-03-19 14:58:01Java中Map使用/渠道ID /** * 渠道ID */ private static final Map<String, String> channelIdAndKey = new HashedMap() { { List<String> channelIDs = Arrays.asList(... -
java map 使用详解
2012-05-19 18:56:48import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set;...public class KeysetTest { ...//map使用 @SuppressWarnings("unchecked") public static void main(Stri -
java ImmutableMap使用
2018-12-14 08:49:24ImmutableMap:一个不可变集合 java中的Immutable对象: 简单地说,如果一个对象实例不能被更改就是一个Immutable的对象,Java SDK提供的大量值对象,比如String等都是Immutable的对象。 创建ImmutableMap: ... -
c++ map使用
2014-01-21 16:56:47最近学习中需要用到stl map和vector,所以此处就整理了下,把它封装成一个类,方便自己以后使用,后面会加上vector的使用 map_class.h代码: #ifndef MAP_CLASS_H #define MAP_CLASS_H /* C++ Maps是一种关联式... -
【Map使用】HashMap的基本使用,什么时候使用Map?
2016-12-27 23:38:47什么时候使用Map? 当存在映射关系时 比如:每个学生对应一个地址 */package com.Map; import java.util.*; class StudentHM //先定义一个学生类 { private String name; private int age; public ... -
erlang map 使用
2016-01-28 00:14:20主要是遇到 Map匹配的问题,所以顺便回忆一下 Erlang 中的映射组 Map,在其它语言中被称作 Hash 哈希或者 Dict 字典。 Erlang 从 R17 版本开始支持映射组 创建映射组 Erlang 中的映射组用结构 #{} 表示,创建... -
C++ map使用详解
2015-09-13 14:04:20使用map简介包含头文件#include <map> map是使用红黑树实现的。她的访问,查找和删除操作的复杂度都是O(logn). -
map使用方法
2015-04-22 22:21:34#include #include #include #include using namespace std;...//创建一个map(键=>值)容器 //m['键1'] = "值1"; srand(unsigned int(time(NULL))); for (int i = 0; i ; i++)//初始化 m[i] = ra -
nginx中map使用方法
2019-06-19 17:43:51本文为转载文章 ... map 指令介绍: map 指令是由 ngx_http_map_module 模块提供的,默认情况下安装 ...map 的主要作用是创建自定义变量,通过使用 nginx 的内置变量,去匹配某些特定规则,如果匹配成功则设置某... -
SourceMap 使用教程
2018-07-18 14:20:12真的是一个很好用的bug监控费服务,众多大佬公司都在使用。 1. 前言 SourceMap 一个存储源代码与编译代码对应位置映射的信息文件 在前端的工作中主要是用来解决以下三个方面出现的 debug 问题: a. 代码... -
golang sync.Map 使用
2019-04-20 13:48:02自1.9版本以后提供了sync.Map,支持多线程并发读写,比之前的加锁map性能要好一点。 提供一下几个方法: type Map //删除指定key func (m *Map) Delete(key interface{}) //查询指定key func (m *Map) Load... -
ES6之Map使用
2018-11-14 21:20:53这种集合,将key映射到指定的值上,在不同的编程语言中具有不同的名称,通常称为字典或Map。 在JavaScript中如何有效地管理这种定位呢?一种传统的定位方法是利用对象是属性名和属性值的特性。 创建如下字典:... -
TileMap使用细节
2017-11-10 17:20:32TileMap每个图块层只能对应一张纹理,所以多张纹理需要建立多个图块层对应。 碰撞检测方式大致2种: 1 以网格为单位的碰撞 2 使用对象层的矩形,线段,点等信息组成的碰撞区域 如果为了智能寻路,那么可能需要以... -
Golang线程安全Map:sync.Map使用小结
2019-03-04 11:13:23转载自: https://blog.csdn.net/u010230794/article/details/82143179 ... sync.Map的使用: package main import ( "sync" "fmt" ) func main() { //开箱即用 var sm sync.Map ... -
kubernetes系列之ConfigMap使用方式
2020-08-10 09:31:08mysql容器重要的文件有两部分,一部分为存储数据文件,一部分为配置文件my.cnf,存储数据可以用持久存储实现和容器的分离解耦,配置文件也能够实现和容器的分离解耦,也就是说mysql容器能够直接读取并使用预先配置好的... -
Java 各类Map使用场景之Map概述
2017-04-05 14:40:22Map隶属java.util包,util包是包含了collection框架,遗留的collection类、时间模型、日期和时间、国际化和各种工具类(字符串标记生成器、随机数生成器和位数组.Map在java中是一个接口。取代了Dictionary类,后者... -
Vue Baidu Map使用
2018-12-11 17:01:54百度地图官方提供的是常规&lt;script&gt;标签引入的方法。要想将百度地图引入Vue中,...这样,在页面中就可以像常规的页面那样使用百度地图了。需要为容器&lt;div&gt;设置一个id属... -
C++ unordered_map使用问题
2019-01-13 17:02:02第一次使用unordered_map 最开始引入#include<unordered_map>,但是报错:[Error] 'unordered_map' was not declared in this scope 解决办法: 引入#include<tr1/unordered_map>... -
C++ map使用详细版
2018-08-21 20:25:41经过几个小时的学习以及测试,map的基本结构是熟悉,但是要想达到灵活运用恐怕还需要进一步练习。以后在涉及到C++中的哈希表时候,用map做代替. 可以横向对比一下vector,大同小异。 1 定义:键值一一对应,key不... -
map使用不存在的下标
2019-02-20 19:17:51当用访问map存在的下标时,大家都指的答案。当访问不存在的下标时,又会发生什么呢?来看下 #include <iostream> #include <map> #include <string> using namespace ... -
k8s-ConfigMap使用
2018-09-14 09:05:04ConfigMap的用处: 1. 生成为容器内的环境变量 2. 设置容器启动的命令参数 3. volume形式挂载成容器内的文件或目录 1.通过yml文件创建一个configmap: 2. 通过命令行创建 kubectl create conf... -
一个hash_map使用错误
2006-07-20 16:44:00一个hash_map使用错误g++的 hash_map 运行不起来#include #include using namespace std;using namespace __gnu_cxx;namespace __gnu_cxx{ template { size_t operator()(const string& s) const -
Map 使用 Lambda 的 forEach 如何跳出循环
2020-06-01 14:42:50Lambda 的 forEach表达式用起来很爽啊,最近开发中用来遍历了一下Map,结果就翻车了......大致场景如下: public static void main(String[] args) { HashMap<String,String> map = new HashMap<>(); ... -
Unity3D-Tilemap初体验(Unity自带Tilemap使用体验)
2018-03-13 16:34:54最近新项目需要做一个用到瓦片地图的游戏,第一想法就是要用Tilemap,之前Unity没有自带的Tilemap,都是第三方插件。知道去年2017.2发布,就有自带的Tilemap啦!将Unity升级到2017.3.1,Tilemap的基本操作,其实API... -
std 之 map 使用总结
2013-05-17 14:00:12map 是一种关联容器, 提供一对一的关联, 关联的形式为: KEY----VALUE 关键字不重复。multimap与map类似,但是允许关键字重复 即:关键字和与之对应的值 关键字起到索引的作用, 在map中查找记录 就是根据...
-
课程设计 航空订票管理系统 C语言 数据结构与算法大作业【文档+源码】
-
算法导论(基础知识)——编程大牛的必经之路
-
中国区域GIS地图下载
-
转行做IT-第6章 IDEA、方法
-
基于Mysql中间件的主从架构(Linux+Mycat+docker+finalshell)
-
舰船磁场信号采集电路的设计
-
阿里云云计算ACP考试必备教程
-
Nginx优化
-
Lamda表达式
-
面向大容量存储的SpaceWire传输层协议设计
-
Python字符串:str.startswith(prefix[, start[, end]])和str.endswith(suffix[, start[, end]])
-
W3School离线手册_2.7z
-
极客大学java进阶训练营
-
「汇编语言 第 3 版 王爽」- 参考答案:检测点 16.2 @20210126
-
pyechart数据可视化
-
基于ZGS的大规模多智能体系统的分布式优化算法
-
Redis数据库入门与使用
-
E - New Year Candles
-
基于总散射测量的表面质量检测新方法
-
8086处理器应用仿真:EMU8086.rar