教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Golang 解决 Map 并发读写安全问题

Golang 解决 Map 并发读写安全问题

发布时间:2021-12-08   编辑:jiaochengji.com
教程集为您提供Golang 解决 Map 并发读写安全问题等资源,欢迎您收藏本站,我们将为您提供最新的Golang 解决 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><h2>一、错误案例</h2> <pre><code class="lang-go hljs"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"fmt"</span> <span class="token string">"time"</span> <span class="token punctuation">)</span> <span class="token keyword">var</span> TestMap <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">string</span><span class="token punctuation">]</span><span class="token builtin">string</span> <span class="token keyword">func</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> TestMap <span class="token operator">=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">string</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">1000</span><span class="token punctuation">;</span> i<span class="token operator"> </span> <span class="token punctuation">{</span> <span class="token keyword">go</span> <span class="token function">Write</span><span class="token punctuation">(</span><span class="token string">"aaa"</span><span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token function">Read</span><span class="token punctuation">(</span><span class="token string">"aaa"</span><span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token function">Write</span><span class="token punctuation">(</span><span class="token string">"bbb"</span><span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token function">Read</span><span class="token punctuation">(</span><span class="token string">"bbb"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span><span class="token number">5</span> <span class="token operator">*</span> time<span class="token punctuation">.</span>Second<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">Read</span><span class="token punctuation">(</span>key <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>TestMap<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">Write</span><span class="token punctuation">(</span>key <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> TestMap<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> key <span class="token punctuation">}</span> </code></pre>

上面代码执行大概率出现报错:fatal error: concurrent map writes

<h2>
二、问题分析</h2>

网上关于 golang 编程中 map 并发读写相关的资料很多,但总是都说成 并发读写 造成上面的错误,到底是 并发读 还是 并发写 造成的,这个很多资料都没有说明。

我们把上面的案例分别在循环中注释 Read 和 Write 函数的调用,分别测试 并发读 和 并发写;

循环次数分别测试了 100、1 w、100 w 次,并发读操作绝对不会报上面的错,而并发写基本都会报错。

因此,这个错误主要原因是:map 并发写。

<h2>
三、问题原因</h2>

为什么 map 并发写会导致这个错误? 网络上的相关文章也大都有说明。

因为 map 变量为 指针类型变量,并发写时,多个协程同时操作一个内存,类似于多线程操作同一个资源会发生竞争关系,共享资源会遭到破坏,因此golang 出于安全的考虑,抛出致命错误:fatal error: concurrent map writes。

<h2>
四、解决方案</h2>

网上各路资料解决方案较多,主要思路是通过加锁保证每个协程同步操作内存。

github 上找到一个 concurrentMap 包,案例代码修改如下:

<pre><code class="lang-go hljs"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"fmt"</span> cmap <span class="token string">"github.com/orcaman/concurrent-map"</span> <span class="token string">"time"</span> <span class="token punctuation">)</span> <span class="token keyword">var</span> TestMap cmap<span class="token punctuation">.</span>ConcurrentMap <span class="token keyword">func</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> TestMap <span class="token operator">=</span> cmap<span class="token punctuation">.</span><span class="token function">New</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">100</span><span class="token punctuation">;</span> i<span class="token operator"> </span> <span class="token punctuation">{</span> <span class="token keyword">go</span> <span class="token function">Write</span><span class="token punctuation">(</span><span class="token string">"aaa"</span><span class="token punctuation">,</span> <span class="token string">"111"</span><span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token function">Read</span><span class="token punctuation">(</span><span class="token string">"aaa"</span><span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token function">Write</span><span class="token punctuation">(</span><span class="token string">"bbb"</span><span class="token punctuation">,</span> <span class="token string">"222"</span><span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token function">Read</span><span class="token punctuation">(</span><span class="token string">"bbb"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span><span class="token number">5</span> <span class="token operator">*</span> time<span class="token punctuation">.</span>Second<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">Read</span><span class="token punctuation">(</span>key <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> v<span class="token punctuation">,</span> ok <span class="token operator">:=</span> TestMap<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span> ok <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">"键值为 %s 的值为:%s"</span><span class="token punctuation">,</span> key<span class="token punctuation">,</span> v<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <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">"键值不存在"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">Write</span><span class="token punctuation">(</span>key <span class="token builtin">string</span><span class="token punctuation">,</span> value <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> TestMap<span class="token punctuation">.</span><span class="token function">Set</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre> <h2>
五、思考总结</h2>

因为我是以 PHP 打开的编程世界,PHP 语言只有单线程,且不涉及指针操作,变量类型也是弱变量,以 PHP 编程思维刚开始接触 Golang 时还比较容易上手,但越往后,语言的特性区别就体现得越来越明显,思维转变就越来越大,对我来说是打开了一个新世界。

像本文出现的错误案例,也是因为自己没有多线程编程的思维基础,导致对这种问题不敏感,还是花了蛮多时间理解的。希望对和我有相似学习路线的朋友提供到一些帮助。

到此这篇关于“Golang 解决 Map 并发读写安全问题”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Golang的map并发安全
golang key map 所有_谨慎使用golang中的map
golang 并发访问map遇到的问题
Golang map 并发读写问题源码分析
go二维map_Golang使用Map的正确姿势
golang map 锁_golang中线程安全的map
golang map 锁_Golang线程安全的map
Golang线程安全Map:sync.Map使用小结
golang中map的一些注意事项
golang map并发读写问题踩坑记录 `concurrent map read and map write`

[关闭]
~ ~