首页 > 其他分享 >在 Go 语言中,构造一个并发安全的 map 集合

在 Go 语言中,构造一个并发安全的 map 集合

时间:2024-10-23 20:32:38浏览次数:5  
标签:wg map 10 int value 并发 func Go

Map 集合是 Go 中提供的一个 KV 结构的数据类型,对它的操作在实际的开发中应该是非常多的,不过它不是一个线程安全的。

1 、Map 不是线程安全的

编写下面的测试代码:

func TestUnsafeMap(t *testing.T) {  
    // 创建一个线程不安全的map  
    myMap := make(map[int]int)  
  
    // 创建一个WaitGroup用于等待所有goroutine完成  
    var wg sync.WaitGroup  
  
    // 启动多个goroutine并发访问map  
    for i := 0; i < 5; i++ {  
       wg.Add(1)  
       go func(i int) {  
          defer wg.Done()  
          myMap[i] = i * 10                               // 向map中写入数据  
          fmt.Printf("Key: %d, Value: %d\n", i, myMap[i]) // 读取map中的数据  
       }(i)  
    }  
  
    // 等待所有goroutine完成  
    wg.Wait()  
  
    // 检查map中的值是否正确(这一步是为了模拟测试)  
    for i := 0; i < 5; i++ {  
       if myMap[i] != i*10 {  
          t.Errorf("Expected %d but got %d", i*10, myMap[i])  
       }  
    }  
}

在上面的代码中,虽然只是循环了很少的次数,就很容易出现竞争问题,错误信息类似下面的:

=== RUN   TestUnsafeMap
Key: 4, Value: 40
Fatal error: concurrent map writesKey: 0, Value: 0

Key: 2, Value: 20
Key: 1, Value: 10 t

2 、构建线程安全的 Map

在 Go 中,为了实现一个线程安全的 map 操作,可以使用 sync.Map 或者通过互斥锁(sync.Mutex)来实现。下面的示例代码是使用锁来手动实现的:

  
type SaleMap struct {  
    mu sync.Mutex  
    m  map[int]int  
}  
  
func NewSaleMap() *SaleMap {  
    return &SaleMap{m: make(map[int]int)}  
}  
  
func (s *SaleMap) Set(key int, value int) {  
    s.mu.Lock()  
    defer s.mu.Unlock()  
    s.m[key] = value  
}  
  
func (s *SaleMap) Get(key int) (int, bool) {  
    s.mu.Lock()  
    defer s.mu.Unlock()  
    value, ok := s.m[key]  
    return value, ok  
}  

然后编写单测如下:

func TestConcurrentMap(t *testing.T) {  
    // 创建一个线程安全的map  
    safeMap := NewSaleMap()  
    var wg sync.WaitGroup  
    // 启动多个goroutine并发写入和读取数据  
    for i := 0; i < 500000; i++ {  
       wg.Add(1)  
       go func(i int) {  
          defer wg.Done()  
          safeMap.Set(i, i*10) // 向map中写入数据  
       }(i)  
    }  
    // 等待所有goroutine完成  
    wg.Wait()  
  
    // 检查map中的值是否正确(这一步是为了模拟测试)  
    for i := 0; i < 500000; i++ {  
       if value, _ := safeMap.Get(i); value != i*10 {  
          t.Errorf("Expected %d but got %d", i*10, value)  
       }  
    }  
}

这一次,循环了更多次,不会再有并发问题了。

Over!

标签:wg,map,10,int,value,并发,func,Go
From: https://www.cnblogs.com/denglei1024/p/18498299

相关文章

  • Go语言中方法是什么?
    在Go语言中,方法是附属于某种类型的函数,也就是说,方法与接收者(receiver)绑定,它可以是结构体类型或自定义类型。方法和函数的主要区别在于方法有一个特殊的接收者参数,而普通的函数没有。1.Go中的方法定义Go语言的方法是通过在函数名前面加上一个接收者参数来定义的。接收者可以是......
  • 18 质量保证:Go 语言如何通过测试保证质量
    从这节课开始,我会带你学习本专栏的第四模块:工程管理。现在项目的开发都不是一个人可以完成的,需要多人进行协作,那么在多人协作中如何保证代码的质量,你写的代码如何被其他人使用,如何优化代码的性能等,就是第四模块的内容。这一讲首先来学习Go语言的单元测试和基准测试。单元......
  • 更改Google谷歌浏览器安装位置
    谷歌浏览器默认是安装C盘的,越用占用的空间越大,所以需要手动迁移到非系统盘。1、在官网下载安装包:GoogleChrome网络浏览器2、下载后,双击安装,默认安装到C盘里面的,中途不能自定义安装。3、安装好后会在桌面生成一个谷歌浏览器的快捷方式:将鼠标移到谷歌浏览器快捷方式图标上→......
  • 2024-10-23:最高频率的 ID。用go语言,给定两个长度相等的整数数组 nums 和 freq, 其中num
    2024-10-23:最高频率的ID。用go语言,给定两个长度相等的整数数组nums和freq,其中nums中的每个元素表示一个ID,而freq中的每个元素表示对应ID在此次操作后出现的次数变化。如果freq[i]为正数,则表示在这次操作中nums[i]的ID会增加freq[i]次;如果freq[i]为负数,则表示在这次操作中nums[i......
  • 并发面试题-谈谈你对AQS的理解
    简要回答AQS(AbstractQueuedSynchronizer抽象队列同步器)是Java并发包中的一个核心组件,它提供了一个框架用于实现基于FIFO等待队列的阻塞锁和同步器。AQS通过管理一个同步状态和一个等待队列来控制多线程对共享资源的访问。它定义了一系列模板方法,如tryAcquire、tryRelease等,供......
  • django传统项目引入bootstrap
    1.使用bootstrapv3:下载bootstrap的css,bootstrap的js,jquery引入<%@pagecontentType="text/html;charset=UTF-8"language="java"%><html><head><title>Title</title><linkrel="stylesheet"hre......
  • flask+python+html+mongodb
     python运行此文件,跳转到index.htmlfromflaskimportFlask,render_template,request,jsonify,json,url_for,redirectapp=Flask(__name__)@app.route('/',methods=['GET','POST'])defindex():returnrender_template('index.......
  • Protocol Buffer Error on compile during GOOGLE_PROTOBUF_MIN_PROTOC_VERSION check
    ProtocolBufferErroroncompileduringGOOGLE_PROTOBUF_MIN_PROTOC_VERSIONcheck出现这个问题一般是安装了多个版本protobufhttps://stackoverflow.com/questions/35744529/protocol-buffer-error-on-compile-during-google-protobuf-min-protoc-version-checkhttps://b......
  • 基于Django+Python的宾馆管理系统设计与实现
    项目运行需要先安装Python的相关依赖:pymysql,Django==3.2.8,pillow使用pipinstall安装第一步:创建数据库第二步:执行SQL语句,.sql文件,运行该文件中的SQL语句第三步:修改源代码中的settings.py文件,改成自己的mysql数据库用户名和密码第四步:运行命令:pythonmanage.pyrunser......
  • Unity Shader-GodRay,体积光(BillBoard,Volume Shadow,Raidal Blur,Ray-Marching)
    前言好久没有更新博客了,经历了不少事情,好在最近回归了一点正轨,决定继续UnityShader的学习之路。作为回归的第一篇,来玩一个比较酷炫的效果(当然废话也比较多),一般称之为GodRay(圣光),也有人叫它云隙光,还有人叫它体积光(探照灯)。这几个名字对应几种类似的效果,但是实现方式相差甚远。先来......