Go语言 sync.Map(在并发中使用)

Go语言中的 map 在并发情况下,只读是线程安全的,同时读写是线程不安全的。

需要并发读写时,一般的做法是加锁,但这样性能并不高,Go语言在 1.9 版本中提供了一种效率较高的并发安全的 sync.Map,sync.Map 和 map 不同,不是以语言原生形态提供,而是在 sync 包下的特殊结构。

sync.Map 有以下特性:

    • 无须初始化,直接声明即可。
    • sync.Map 不能使用 map 的方式进行取值和设置等操作,而是使用 sync.Map 的方法进行调用,Store 表示存储,Load 表示获取,Delete 表示删除。
    • 使用 Range 配合一个回调函数进行遍历操作,通过回调函数返回内部遍历出来的值,Range 参数中回调函数的返回值在需要继续迭代遍历时,返回 true,终止迭代遍历时,返回 false。

并发安全的 sync.Map 演示代码如下:

package main

import (
    "fmt"
    "sync"
)

func main() {  
    var score sync.Map 

    // 将键值对保存到sync.Map
    score.Store("语文", 66)
    score.Store("数学", 86)
    score.Store("英语", 36)
    //从map中根据键取值
    fmt.Println(score.Load("数学"))
    //从map中根据键删除元素
    score.Delete("数学")

    score.Range(func(k, v interface{}) bool {
        fmt.Println("iterate:", k, v)
        return true
    })

}

代码输出如下:

86 true
iterate: 英语 36
iterate: 语文 66

注意:

声明 score,类型为 sync.Map,注意,sync.Map 不能使用 make 创建。

将一系列键值对保存到 sync.Map 中,sync.Map 将键和值以 interface{} 类型进行保存。

Range() 方法可以遍历 sync.Map,遍历需要提供一个匿名函数,参数为 k、v,类型为 interface{},每次 Range() 在遍历一个元素时,都会调用这个匿名函数把结果返回。

sync.Map 没有提供获取 map 数量的方法,替代方法是在获取 sync.Map 时遍历自行计算数量,sync.Map 为了保证并发安全有一些性能损失,因此在非并发情况下,使用 map 相比使用 sync.Map 会有更好的性能。

原文地址:https://www.cnblogs.com/personblog/p/12254867.html

时间: 2024-10-17 22:14:08

Go语言 sync.Map(在并发中使用)的相关文章

go语言学习--map的并发

go提供了一种叫map的数据结构,可以翻译成映射,对应于其他语言的字典.哈希表.借助map,可以定义一个键和值,然后可以从map中获取.设置和删除这个值,尤其适合数据查找的场景.但是map的使用有一定的限制,如果是在单个协程中读写map,那么不会存在什么问题,如果是多个协程并发访问一个map,有可能会导致程序退出,并打印下面错误信息: fatal error: concurrent map read and map write 上面的这个错误不是每次都会遇到的,如果并发访问的协程数不大,遇到的可

Golang并发中channel的分析

问题:面对并发问题,是用channel解决,还是用Mutex解决? 如果自己心里还没有清晰的答案,那就读下这篇文章,你会了解到: 使用channel解决并发问题的核心思路和示例 channel擅长解决什么样的并发问题,Mutex擅长解决什么样的并发问题 一个并发问题该怎么入手解解决 一个重要的plus思维 前戏 前面很多篇的文章都在围绕channel介绍,而只有前一篇sync的文章介绍到了Mutex,不是我偏心,而是channel在Golang是first class级别的,设计在语言特性中的,

Go36-34,35-并发安全字典(sync.Map)

并发安全字典(sync.Map) 之前的几篇,几乎已经把Go语言自带的同步工具都讲过了.这篇要讲的是一个并发安全的高级数据结构:sync.Map. 原生字典 Go语言自带的字典类型map,就是原生字典,并不是并发安全的. 在使用原生字典的时候,应该在启动goroutine之前就完成字典的初始化和赋值.或者更高级的做法是,可以在goroutine中,在首次使用的时候通过sync.Once来并发安全的完成初始化和赋值的操作,达到一个延迟初始化的优化效果.之后在使用字典的时候,就只能获取其中的内容,不

深度解密Go语言之 map

目录 什么是 map 为什么要用 map map 的底层如何实现 map 内存模型 创建 map 哈希函数 key 定位过程 map 的两种 get 操作 如何进行扩容 map 的遍历 map 的赋值 map 的删除 map 进阶 可以边遍历边删除吗 key 可以是 float 型吗? 总结 参考资料 这篇文章主要讲 map 的赋值.删除.查询.扩容的具体执行过程,仍然是从底层的角度展开.结合源码,看完本文一定会彻底明白 map 底层原理. 我要说明的是,这里对 map 的基本用法涉及比较少,我

sync.Map源码分析

sync.Map源码分析 背景 众所周知,go普通的map是不支持并发的,换而言之,不是线程(goroutine)安全的.博主是从golang 1.4开始使用的,那时候map的并发读是没有支持,但是并发写会出现脏数据.golang 1.6之后,并发地读写会直接panic: fatal error: concurrent map read and map write package main func main() { m := make(map[int]int) go func() { for

GO语言 切片 map 字符串

切片 1.什么是切片 切片本身不拥有任何数据,它们只是对现有数组的引用. 2.切片的定义 1.方式1:由数组切出来:var 变量名 []元素类型 = 数组名[开始值:结束值] //1.定义数组 var a [8]int=[8]int{1,2,3,4,5,6,7,8} //2.定义切片,注意[]中没有数字 var b []int=a[2:6] fmt.Println(b) // [3 4 5 6] //更多用法,没有步长 var a [8]int=[8]int{1,2,3,4,5,6,7,8} b

C#语言基础知识(2):C#中多态

我的理解是:通过继承实现的不同对象调用相同的方法,表现出不同的行为,称之为多态. 1: OverRide 实现多态 1 public class Animal 2 { 3 public virtual void Eat() 4 { 5 Console.WriteLine("Animal eat"); 6 } 7 } 8 public class Dog : Animal 9 { 10 public override void Eat() 11 { 12 Console.WriteLin

【转】Java并发中正确使用volatile

Java并发中正确使用volatile 原文链接 http://ifeve.com/how-to-use-volatile/ 作者:一粟   整理和翻译自Twitter实时搜索的PPT 前几天并发编程群里有同学对volatile的用法提出了疑问,刚好我记得Twitter有关实时搜索的这个PPT对这个问题解释的很清晰并有一个实际的应用场景,于是周末把这个问题摘录了一些和并发相关的内容如下: 并发 – 定义 悲观锁 – Pressimistic locking 一个线性在执行一个操作时持有对一个资源

C#语言基础知识(1):C#中关于重载和重写

Overload:重载就是在同一个类中,方法名相同,参数列表不同.参数列表不同包括:参数的个数不同,参数类型不同. 1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 5 namespace OverLoading 6 { 7 class Program 8 { 9 public static int max(int i, int j) //静态方法 10 { 11 if (i > j) 12 re