golang map非线程安全

golang map

对于很多人来说golang这种天然友好支持goroutine的语言竟然不原生支持原子访问map可能有一些匪夷所思毕竟连cpp都支持线程访问(并不保证线程安全),如下来自官方文档的说法,其实仔细读一读就会发现,这种事情确实还是程序员自己来做比较好,毕竟golang致力于像C一样精简,在代码的逻辑协调这一方面还是交给程序员来控制比较好:)

Why are map operations not defined to be atomic?

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

The language does not preclude atomic map updates. When required, suchas when hosting an untrusted program, the implementation could interlockmap access.

在golang中如果是对于一个map同是进行了read/write那么程序会直接panic,因为此时代码的运行结果是非预期的,所以第一种大家能想到的最直接的方法当然是使用sync的加锁啦:),有人使用这种方法封装了一个current_map,链接,其原理就是将map常用的操作封装起来在方法里面调用加锁、开锁的操作,在使用者看来是省掉了锁这一步骤,大致看了一下代码,就不再细说了。

但是想起之前学习golang的时候以及在使用过程中,golang的设计哲学一直是尽量避免使用锁而尽可能的利用channel的io阻塞来进行协调,因此后来我又想出来这第二种方法,并且此方法仅限于golang,:)简直漂亮,以下为思路:

使用channel来使对于map的访问串行化,确保只有一个goroutine对于map进行访问,可以把这个goroutine理解为map的管理线程,任何对于map的访问都以数据结构的方式写入channel,之后管理routine根据传值进行处理,例如传进来的数据结构为,如下,管理routine根据action的取值操作map,同时get方法<- es.c,当管理线程把key的取值赋值给data之后像es.c里面写入一个bool来通知取值结束,一个简单的思路:),后来搜了一下有找到相关的实现方法

由于第一种方法萌生了一种实现通用goroutine map的想法~~~😆

1
2
3
4
5
6
7
> type es struct{
> action int
> key string
> data *int
> c chan bool
> }
>

>