教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Golang map线程安全实现及sync.map使用及原理解析。

Golang map线程安全实现及sync.map使用及原理解析。

发布时间:2021-12-17   编辑:jiaochengji.com
教程集为您提供Golang map线程安全实现及sync.map使用及原理解析。等资源,欢迎您收藏本站,我们将为您提供最新的Golang map线程安全实现及sync.map使用及原理解析。资源
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"/></svg>

<h3>文章目录</h3> <ul><li>前言</li><li>一、为什么map线程不安全?</li><li>二、配合(锁)实现线程安全的map。</li><li><ul><li>1.悲观锁的形式</li><li>2.乐观锁的形式</li><li>3.根据map实现原理,对小范围进行加锁。</li></ul></li><li>三、sync.map实现的原理。</li><li><ul><li>1、sync.Map 的实现原理可概括为:</li><li><ul><li>       a、过 read 和 dirty 两个字段将读写分离,读的数据存在只读字段 read 上,将最新写入的数据则存在 dirty 字段上</li><li>       b、读取时会先查询 read,不存在再查询 dirty,写入时则只写入 dirty</li><li>       c、读取 read 并不需要加锁,而读或写 dirty 都需要加锁</li><li>       d、另外有 misses 字段来统计 read 被穿透的次数(被穿透指需要读 dirty 的情况),超过一定次数则将 dirty 数据同步到 read 上</li><li>       e、对于删除数据则直接通过标记来延迟删除</li></ul></li><li>2、sync.Map 使用方法:</li></ul></li><li>总结</li></ul>


<h1>前言</h1>

       众所周知,Golang 的map是不安全的,所以sync包提供了线程安全的map。接下来就是把我对sync.map的理解写出来分享给各位。


<h1>
一、为什么map线程不安全?</h1>

       map不是线程安全的。在同一时间段内,让不同 goroutine 中的代码,对同一个字典进行读写操作是不安全的。字典值本身可能会因这些操作而产生混乱,相关的程序也可能会因此发生不可预知的问题。

<h1>
二、配合(锁)实现线程安全的map。</h1> <h2>1.悲观锁的形式</h2>

悲观锁:进来的每一步操作都认为同时会有其他进程影响操作,所以提前加锁。

<pre><code class="lang-c hljs">lock<span class="token punctuation">.</span><span class="token function">Lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//map的增删改查操作</span> lock<span class="token punctuation">.</span><span class="token function">UnLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </code></pre> <h2>
2.乐观锁的形式</h2>

乐观锁:因为map线程不安全是同时:读&&写||写&&写 造成的,所以在map写的时候加上锁就会提高map的性能。

<pre><code class="lang-c hljs"><span class="token comment">//查</span> lock<span class="token punctuation">.</span><span class="token function">Lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//map的增删改操作</span> lock<span class="token punctuation">.</span><span class="token function">UnLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </code></pre> <h2>
3.根据map实现原理,对小范围进行加锁。</h2>

另一种设想是在buckets层面或者map更基本的组成层面加锁,根据乐观锁的情况进行小范围加锁。这里推荐一篇大佬的文章,写的非常好。(传送)

<h1>
三、sync.map实现的原理。</h1> <h2>1、sync.Map 的实现原理可概括为:</h2> <h3>       a、过 read 和 dirty 两个字段将读写分离,读的数据存在只读字段 read 上,将最新写入的数据则存在 dirty 字段上</h3> <h3>       b、读取时会先查询 read,不存在再查询 dirty,写入时则只写入 dirty</h3> <h3>       c、读取 read 并不需要加锁,而读或写 dirty 都需要加锁</h3> <h3>       d、另外有 misses 字段来统计 read 被穿透的次数(被穿透指需要读 dirty 的情况),超过一定次数则将 dirty 数据同步到 read 上</h3> <h3>       e、对于删除数据则直接通过标记来延迟删除</h3> <h2>2、sync.Map 使用方法:</h2> <pre><code class="lang-c hljs"> var ma sync<span class="token punctuation">.</span>Map<span class="token comment">// 该类型是开箱即用,只需要声明既可</span> ma<span class="token punctuation">.</span><span class="token function">Store</span><span class="token punctuation">(</span><span class="token string">"key"</span><span class="token punctuation">,</span> <span class="token string">"value"</span><span class="token punctuation">)</span> <span class="token comment">// 存储值</span> ma<span class="token punctuation">.</span><span class="token function">Delete</span><span class="token punctuation">(</span><span class="token string">"key"</span><span class="token punctuation">)</span> <span class="token comment">//删除值</span> ma<span class="token punctuation">.</span><span class="token function">LoadOrStore</span><span class="token punctuation">(</span><span class="token string">"key"</span><span class="token punctuation">,</span> <span class="token string">"value"</span><span class="token punctuation">)</span><span class="token comment">// 获取值,如果没有则存储</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>ma<span class="token punctuation">.</span><span class="token function">Load</span><span class="token punctuation">(</span><span class="token string">"key"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment">//获取值</span> <span class="token comment">//遍历</span> ma<span class="token punctuation">.</span><span class="token function">Range</span><span class="token punctuation">(</span><span class="token function">func</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value interface<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span> bool <span class="token punctuation">{</span> fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"key:%s ,value:%s \n"</span><span class="token punctuation">,</span> key<span class="token punctuation">,</span> value<span class="token punctuation">)</span> <span class="token comment">//如果返回:false,则退出循环,</span> <span class="token keyword">return</span> true <span class="token punctuation">}</span><span class="token punctuation">)</span> </code></pre>
<h1>
总结</h1>

        map底层虽然写的尤为漂亮,但是为了效率,没有把线程安全安排上,所以另外加了sync.map,兼容线程安全。在我的理解中,sync.map实现就是依靠两张map对读操作和写操作分离,后续根据需要在把dirty map合入 read map中。相对于乐观锁实现的方式,写进程执行的时候,读进程也可能在read map上进行。
        如有问题请联系本人指正,谢谢~

到此这篇关于“Golang map线程安全实现及sync.map使用及原理解析。”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Golang map线程安全实现及sync.map使用及原理解析。
通过实例深入理解sync.Map的工作原理
golang key map 所有_golang系列——高级语法之map
golang map 锁_Golang线程安全的map
golang map 锁_golang中线程安全的map
Golang map 并发读写问题源码分析
Golang线程安全Map:sync.Map使用小结
go二维map_Golang使用Map的正确姿势
golang key map 所有_谨慎使用golang中的map
Golang中sync.Map的实现原理

[关闭]
~ ~