Golang 线程安全与 sync.Map

前言

线程安全通常是指在并发环境下,共享资源的访问被适当地管理,以防止竞争条件(race conditions)导致的数据不一致

Go语言中的线程安全可以通过多种方式实现

实现方式

  1. 互斥锁(Mutexes)
    Go的sync包提供了Mutex和RWMutex类型来确保在一个时间点只有一个协程可以访问某个资源
go 复制代码
import "sync"

var mu sync.Mutex
var sharedResource map[string]int

func updateResource(key string, value int) {
    mu.Lock()         // 加锁
    sharedResource[key] = value
    mu.Unlock()       // 解锁
}
  1. 原子操作(Atomic operations)
    sync/atomic包提供了一系列原子操作函数,可用于管理基本数据类型的并发访问
go 复制代码
import "sync/atomic"

var count int64

func increment() {
    atomic.AddInt64(&count, 1) // 原子地增加计数
}
  1. 通道(Channels)
    通过使用通道,可以在协程之间安全地传递数据。当数据通过通道从一个协程传递到另一个协程时,不需要额外的同步机制
go 复制代码
ch := make(chan int)

// 发送者
go func() {
    ch <- 42
}()

// 接收者
go func() {
    value := <-ch
    fmt.Println(value)
}()
  1. 不可变性(Immutability)

    不修改数据可以自然地避免并发问题。设计数据结构和算法时,尽可能使数据不可变,可以减少同步的需要

  2. 其他同步原语

    sync包还提供了其他同步原语,如WaitGroup、Once、Cond等,可以用来同步协程的不同行为

使用上述任何一种机制时,都需要仔细设计代码以避免死锁、活锁或饥饿等问题。在Go中,可以使用go run -race命令来检测代码中的竞争条件

sync.Map

sync.Map 是一个线程安全的映射(map),它是在 sync 包中提供的。与使用互斥锁来保护普通的 map 不同,sync.Map 使用了一种无锁的技术,特别适用于以下两种场景:

  1. 当给定键的条目只写入一次但读取多次时,比如在全局缓存中
  2. 当多个协程读取、写入和覆盖不相交的键集的条目时

sync.Map 提供了一些内置方法来操作线程安全的键值对:

  • Store(key, value): 存储键值对
  • Load(key): 根据键获取值
  • LoadOrStore(key, value): 获取或存储键值对。如果键已经存在,则返回现有的键值对和 false;如果不存在,则存储并返回键值对和 true
  • Delete(key): 删除键值对
  • Range(f func(key, value interface{}) bool): 遍历所有键值对,对每个键值对执行给定的函数 f

看下基本用法

go 复制代码
import (
    "fmt"
    "sync"
)

func main() {
    var sm sync.Map

    // 存储键值对
    sm.Store("hello", "world")
    sm.Store(1, 3)

    // 读取键对应的值
    if value, ok := sm.Load("hello"); ok {
        fmt.Println("hello:", value)
    }

    // 删除键
    sm.Delete("hello")

    // 遍历所有键值对
    sm.Range(func(key, value interface{}) bool {
        fmt.Println(key, value)
        return true // 继续遍历
    })
}

请注意,尽管 sync.Map 提供了线程安全的操作,但是它的性能通常会比使用互斥锁保护的普通 map 差,因此只推荐在上述特定场景中使用

相关推荐
无心水34 分钟前
4、Go语言程序实体详解:变量声明与常量应用【初学者指南】
java·服务器·开发语言·人工智能·python·golang·go
漫漫求38 分钟前
1、IM:基础连接
开发语言·后端·golang
源代码•宸12 小时前
Leetcode—509. 斐波那契数【简单】
经验分享·算法·leetcode·面试·golang·记忆化搜索·动规
我不是8神16 小时前
字节跳动 Eino 框架(Golang+AI)知识点全面总结
开发语言·人工智能·golang
zhuhezhang16 小时前
go wails doctor提示Required dependencies missing: libwebkit
golang·wails·libwebkit
2501_9418053119 小时前
使用Python和Go构建高性能分布式任务调度系统的实践分享
分布式·python·golang
有谁看见我的剑了?1 天前
使用 go get github.com/go-sql-driver/mysql 驱动失败
golang
无心水1 天前
2、Go语言源码文件组织与命令源码文件实战指南
开发语言·人工智能·后端·机器学习·golang·go·gopath
阿里云云原生1 天前
阿里云可观测联合 Datadog 发布 OpenTelemetry Go 自动插桩工具
阿里云·golang·云计算·可观测
张丶大帅1 天前
【走进Golang】
开发语言·后端·golang