首页 > 其他分享 >sync.Map实现原理

sync.Map实现原理

时间:2024-11-30 11:45:38浏览次数:6  
标签:Map map read sync 并发 原理 操作

1. 读写分离机制

sync.Map 的内部结构是通过读写分离实现的,主要由两个部分组成:
只读部分(read map):用于存储稳定的数据。读取操作主要从这个只读部分进行,避免锁的使用。
脏数据部分(dirty map):当数据发生修改(写入、删除)时,会被移动到脏数据区域,写入的同时加锁来确保并发安全。

2. 快速读取路径

无锁读取:如果数据已经存在于 read map 中(即稳定的数据),读取操作不需要加锁,这使得 sync.Map 的读操作非常高效。
写时复制:当数据在 read map 中不存在时,可能存在于 dirty map 中。此时需要升级锁并从 dirty map 读取或写入数据。

3. 写入时的锁保护

当需要写入(Store 或 Delete)时,sync.Map 会在 dirty map 中进行操作。写操作会加锁,以确保并发写入时的安全性。
每次写入时,sync.Map 都会检查 read map 和 dirty map 之间的数据是否需要同步(比如数据量超过某个阈值时),并对脏数据部分进行清理和迁移。

4. 懒惰同步(Lazy Synchronization)

当读操作频繁时,sync.Map 会把部分脏数据逐步迁移到 read map,从而减少读操作对锁的依赖。这种延迟同步策略保证了读操作可以尽量避免锁竞争,从而提升读取性能。

5. 原子操作

sync.Map 的部分操作(如 LoadOrStore、LoadAndDelete 等)采用了原子操作。它们的实现使用了底层的原子性检查和赋值操作,确保这些操作能够在并发环境中保持一致性。

读操作 (Load):

首先从 read map 中读取,如果找到,直接返回。
如果在 read map 中没有找到,则会尝试从 dirty map 中读取,同时可能会触发一次锁定操作。

写操作 (Store):

写操作会锁定 sync.Map,以保证在并发环境下对 dirty map 的安全写入。
如果脏数据变多或写入频繁,可能会触发 read map 的同步,将一些脏数据迁移到 read map。

删除操作 (Delete):

删除操作也会加锁,并删除 dirty map 中的数据。

批量操作 (Range):

Range 操作遍历 sync.Map 中的所有数据,确保在遍历期间不会发生并发冲突。

代码示例

package main

import (
    "fmt"
    "sync"
)

func main() {
    var m sync.Map

    // 写入数据
    m.Store("foo", 1)
    m.Store("bar", 2)

    // 读取数据
    value, ok := m.Load("foo")
    if ok {
        fmt.Println("foo:", value)
    }

    // 删除数据
    m.Delete("foo")

    // 使用 Range 遍历所有元素
    m.Range(func(key, value interface{}) bool {
        fmt.Println(key, value)
        return true
    })
}

sync.Map 的优点

读性能高:在读多写少的场景下表现非常优异,因为 read map 读取时不需要加锁,减少了锁竞争。
自动并发控制:sync.Map 不需要手动管理锁机制,减少了编写并发安全代码的复杂度。
适合高并发场景:特别是在大量读取的情况下,sync.Map 的性能优于传统的 map + sync.RWMutex 的方案。
何时使用 sync.Map
读多写少的场景:当并发访问主要是读操作,写操作较少时,sync.Map 的读写分离机制使得它具有很高的性能。
需要简单并发访问:当需要并发访问 map,而且不想手动管理锁时,sync.Map 是一个非常方便的工具。

何时不使用 sync.Map

写操作非常频繁:sync.Map 在写操作上需要加锁,如果写操作占比很高,可能不如手动加锁的传统 map 方案效率高。

标签:Map,map,read,sync,并发,原理,操作
From: https://www.cnblogs.com/qcy-blog/p/18578217

相关文章

  • 随机森林:从原理到实践,解锁机器学习 “神器”
    在机器学习的广袤天地里,随机森林犹如一片神秘而强大的智慧丛林,以其卓越的性能、良好的稳定性和广泛的适用性,成为数据科学家们手中的得力“法宝”。今天,就让我们深入这片“丛林”,探寻随机森林背后的奥秘与魅力。随机森林是什么“物种”?随机森林(RandomForest),从本质上讲,属......
  • 举例说明这三种方法map、reduce和filter的区别是什么?
    map、reduce和filter都是JavaScript数组的高阶函数,它们允许你以声明式的方式操作数组,而无需显式地编写循环。它们的主要区别在于它们如何转换数组以及返回的结果:1.map:作用:对数组的每个元素应用一个函数,并返回一个包含转换后元素的新数组。原始数组保持不变。类比:......
  • HCIP-03 Eth-Trunk 技术原理与配置
    目录Eth-Trunk基本原理Eth-Trunk概念手工负载分担模式LACP模式LACP模式活动链路的选取LACP模式的抢占机制Eth-Trunk接口负载分担Eth-Trunk接口配置流程配置手工负载分担模式配置LACP模式Eth-Trunk配置实例核心层设备配置汇聚层设备配置接入层设备配置随着网络中部署的业务量不断......
  • Java基础——泛型(3)#HashMap泛型
    一、HashMap        HashMap最早出现在JDK1.2中,底层基于散列算法实现,它是一个key-value结构的容器。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。二、HashMap特点      ......
  • CompletableFuture.runAsync使用示例
    CompletableFuture.runAsync()是Java8引入的一个方法,它用于异步执行一个任务,并且该任务没有返回值(即返回void)。该方法会启动一个新的线程来执行给定的任务,而不阻塞主线程或调用线程。作用:异步执行:CompletableFuture.runAsync()会在独立的线程中执行一个Runnable任务,......
  • 2025蓝桥杯(单片机)备赛--扩展外设之PWM的原理与应用(十三)
    1PWM原理        PWM:该方法未使用常规的PWM相关的寄存器配置;而是使用了定时器2;与这个类似。周期:通过定时器2设置每次进中断的间隔,来设置最小周期(步进),如设置100us,这时PWM的最小周期为100us,最大频率为1/100us;可通过设置一个变量进行累加,当该变量的值达到一定......
  • 【Go底层】通道原理
    目录1、背景2、go版本3、源码解释【1】chan的底层结构【2】chan初始化【3】往chan发送数据【4】从chan读取数据4、总结1、背景chan可以说是go中非常好用的并发控制模块,并且是并发安全的,采用了CSP思想(通过通信来共享内存,而不是通过共享内存来通信),chan虽然好用,但是......
  • 【Go底层】time包Ticker定时器原理
    目录1、背景2、go版本3、源码解释【1】Ticker结构【2】NewTicker函数解释4、代码示例5、总结1、背景说到定时器我们一般想到的库是cron,但是对于一些简单的定时任务场景,标准库time包下提供的定时器就足够我们使用,本篇文章我们就来研究一下time包下的Ticker定时器。2......
  • 【机器学习算法】GBDT原理及实现
    一、基本内容提升树的分类-二分类问题回归问题模型Adaboost的特例,每个弱分类器的高度为2,并且权重为1损失函数指数损失函数平方误差损失函数优化方式通过经验风险最小化拟合新的弱分类器通过残差拟合新的弱分类器​ 针对不同的问题,不同的损失函数有......
  • JDK17 AbstractQueuedSynchronizer 二 条件队列
    条件队列同步队列中的线程是为了争抢锁,而条件队列中的线程是主动释放锁,挂起自己,等条件满足时被别的线程唤醒,继续工作。AQS里只有1个同步队列,但可以有多个等待队列,每个等待队列对应一个ConditionObject对象。publicstaticvoidmain(String[]args){ ReentrantLocklo......