如何实现一个线程安全的 map?

**题目来源:**学而思

答案1:

三种方式实现:

  • 加读写锁
  • 分片加锁
  • sync.Map

加读写锁、分片加锁,这两种方案都比较常用,后者的性能更好,因为它可以降低锁的粒度,提高访问此 map 对象的吞吐。前者并发性能虽然不如后者,

但是加锁的方式更加简单。sync.Map 是 Go 1.9 增加的一个线程安全的 map ,虽然是官方标准,但反而是不常用的,原因是 map 要解决的场景很难 描述,很多时候程序员在做抉择是否该用它,不过在一些特殊场景会使用 sync.Map,场景一:只会增长的缓存系统,一个 key 值写入一次而被读很多次;

场景二:多个 goroutine 为不相交的键读、写和重写键值对。对它的使用场景介绍,来自官方文档,这里就不展开了。 加读写锁,扩展 map 来实现线程安全,支持并发读写。使用读写锁 RWMutex,是为了读写性能的考虑。 对 map 对象的操作,无非就是常见的增删改查和遍历。我们可以将查询和遍历看作读操作,增加、修改和 删除看作写操作。示例代码链接:https://github.com/guowei-gong/go-demo/blob/main/mutex/demo.go 。通过读写锁提供线程安全的 map,但是大量并发读写的情况下,锁的竞争会很激烈,导致性能降低。如何解决这个问题? 尽量减少锁的粒度和锁的持有时间,减少锁的粒度,常用方法就是分片 Shard,将一把锁分成几把锁,每个锁控制一个分片。