😥 整理不易,此资源只针对正式星主开放,
还请入驻星球后再来观看。

GOLANG ROADMAP

阅读模式

  • 沉浸
  • 自动
  • 日常
首页
Go学习
  • Go学院

    • Go小课
    • Go小考
    • Go实战
    • 精品课
  • Go宝典

    • 在线宝典
    • B站精选
    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
  • Go下载

    • 视频资源
    • 文档资源
Go求职
  • 求职服务

    • 内推互助
    • 求职助力
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
Go友会
  • 城市
  • 校园
推广返利 🤑
实验区
  • Go周边
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
author-avatar

GOLANG ROADMAP


首页
Go学习
  • Go学院

    • Go小课
    • Go小考
    • Go实战
    • 精品课
  • Go宝典

    • 在线宝典
    • B站精选
    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
  • Go下载

    • 视频资源
    • 文档资源
Go求职
  • 求职服务

    • 内推互助
    • 求职助力
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
Go友会
  • 城市
  • 校园
推广返利 🤑
实验区
  • Go周边
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
  • Go真实面试题汇总系列

    • 《Mutex篇》
  • 宝典内容

    • 15. WaitGroup的坑
    • 18. 读写锁底层是怎么实现的
    • 34. go 的锁是可重入的吗?
    • 120. go中的互斥锁:正常、饥饿状态,读写锁中写操作如何阻止读操作?
    • 180. golang 的 waitGroup 用法
    • 225. golang如何知道或者检测死锁
    • 226. 怎么处理锁分段
    • 241. 互斥锁的底层实现
    • 289. go标准库的mutex介绍
    • 366. golang的锁有了解吗?
    • 368. go标准库的mutex介绍

😥 整理不易,此资源只针对正式星主开放,
还请入驻星球后再来观看。

226. 怎么处理锁分段


企业题库解析小组

题目序号:(2270)

题目来源:网易互娱

频次:1

# 答案1:(ORVR)

在golang的原生map是非并发安全的,为了实现了map的并发安全,最安全有效的方式就是给map加锁,如果遇到大数据,高并发的场景下,直接对整个map进行加锁的话,就会显得整个并发访问控制及其缓慢,由此在sync.map还未出来之前,比较流行的做法就是使用分段锁,降低锁的颗粒度,从而使每个分片上的数据读写互不影响,从而提高map整体的读写效率

模拟分段锁实现

// Map 分片

type ConcurrentMap []*ConcurrentMapShared

// 每一个Map 是一个加锁的并发安全Map

type ConcurrentMapShared struct {

    items map[string]interface{}

    sync.RWMutex // 各个分片Map各自的锁

}
1
2
3
4
5
6
7
8
9
10
11
12
13

主流的分段锁,即通过hash取模的方式找到当前访问的key处于哪一个分片之上,再对该分片进行加锁之后再读写。分片定位时,常用有BKDR, FNV32等hash算法得到key的hash值。

func New() ConcurrentMap {

    // SHARD_COUNT 默认32个分片

    m := make(ConcurrentMap, SHARD_COUNT)

    for i := 0; i < SHARD_COUNT; i++ {

        m[i] = &ConcurrentMapShared{

            items: make(map[string]interface{}),

        }

    }
    return m

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

在初始化好分片后, 对分片上的数据进行读写时就需要用hash取模进行分段定位来确认即将要读写的分片。

func (m ConcurrentMap) GetShard(key string) *ConcurrentMapShared {

    return m[uint(fnv32(key))%uint(SHARD_COUNT)]

}

// FNV hash

func fnv32(key string) uint32 {

    hash := uint32(2166136261)

    const prime32 = uint32(16777619)

    for i := 0; i < len(key); i++ {

        hash *= prime32

        hash ^= uint32(key[i])

    }

    return hash

}

func (m ConcurrentMap) Set(key string, value interface{}) {

    shard := m.GetShard(key) // 段定位找到分片

    shard.Lock()       // 分片上锁

    shard.items[key] = value // 分片操作

    shard.Unlock()       // 分片解锁

}

func (m ConcurrentMap) Get(key string) (interface{}, bool) {

    shard := m.GetShard(key)

    shard.RLock()

    val, ok := shard.items[key]

    shard.RUnlock()

    return val, ok

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

由此一个分段锁Map就实现了, 但是比起普通的Map, 常用到的方法比如获取所有key, 获取所有Val 操作是要比原生Map复杂的,因为要遍历每一个分片的每一个数据, 好在golang的并发特性使得解决这类问题变得非常简单

  • 答案1:(ORVR)