扫码订阅《 Go语言面试题精讲》或入驻星球,即可阅读文章!

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语言面试题精讲》
  • Go基础

  • Slice

  • Map

    • 1.Go map的底层实现原理?
    • 2.Go map遍历为什么是无序的?
    • 3.Go map为什么是非线程安全的?
    • 4.Go map如何查找?
    • 5.Go map冲突的解决方式?
    • 6.Go map 的负载因子为什么是 6.5?
    • 7.Go map如何扩容?
    • 8.Go map和sync.Map谁的性能好,为什么?
  • Channel

  • Mutex

  • Goroutine

  • 调度模型

  • 内存管理

  • 并发编程

扫码订阅《 Go语言面试题精讲》或入驻星球,即可阅读文章!

3.Go map为什么是非线程安全的?


caspar
【点击观看视频】Go map为什么是非线程安全的?

map默认是并发不安全的,同时对map进行并发读写时,程序会panic,原因如下:

Go 官方在经过了长时间的讨论后,认为 Go map 更应适配典型使用场景(不需要从多个 goroutine 中进行安全访问),而不是为了小部分情况(并发访问),导致大部分程序付出加锁代价(性能),决定了不支持。

场景: 2个协程同时读和写,以下程序会出现致命错误:fatal error: concurrent map writes

package main

import (
    "fmt"
    "time"
)

func main() {
    s := make(map[int]int)
    for i := 0; i < 100; i++ {
        go func(i int) {
            s[i] = i
        }(i)
    }
    for i := 0; i < 100; i++ {
        go func(i int) {
            fmt.Printf("map第%d个元素值是%d\n", i, s[i])
        }(i)
    }
    time.Sleep(1 * time.Second)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

如果想实现map线程安全,有两种方式:

方式一:使用读写锁 map + sync.RWMutex

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var lock sync.RWMutex
    s := make(map[int]int)
    for i := 0; i < 100; i++ {
        go func(i int) {
            lock.Lock()
            s[i] = i
            lock.Unlock()
        }(i)
    }
    for i := 0; i < 100; i++ {
        go func(i int) {
            lock.RLock()
            fmt.Printf("map第%d个元素值是%d\n", i, s[i])
            lock.RUnlock()
        }(i)
    }
    time.Sleep(1 * time.Second)
}
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

方式二:使用Go提供的 sync.Map

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var m sync.Map
    for i := 0; i < 100; i++ {
        go func(i int) {
            m.Store(i, i)
        }(i)
    }
    for i := 0; i < 100; i++ {
        go func(i int) {
            v, ok := m.Load(i)
            fmt.Printf("Load: %v, %v\n", v, ok)
        }(i)
    }
    time.Sleep(1 * time.Second)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23