惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Forbes - Security
Forbes - Security
A
Arctic Wolf
M
MIT News - Artificial intelligence
T
Threat Research - Cisco Blogs
T
The Exploit Database - CXSecurity.com
C
CERT Recently Published Vulnerability Notes
NISL@THU
NISL@THU
L
Lohrmann on Cybersecurity
Martin Fowler
Martin Fowler
A
About on SuperTechFans
P
Palo Alto Networks Blog
Project Zero
Project Zero
The GitHub Blog
The GitHub Blog
WordPress大学
WordPress大学
Blog — PlanetScale
Blog — PlanetScale
博客园_首页
大猫的无限游戏
大猫的无限游戏
Cisco Talos Blog
Cisco Talos Blog
P
Proofpoint News Feed
D
DataBreaches.Net
Cyberwarzone
Cyberwarzone
T
Tor Project blog
IT之家
IT之家
P
Proofpoint News Feed
Help Net Security
Help Net Security
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
CXSECURITY Database RSS Feed - CXSecurity.com
Microsoft Azure Blog
Microsoft Azure Blog
V2EX - 技术
V2EX - 技术
K
Kaspersky official blog
Hugging Face - Blog
Hugging Face - Blog
MongoDB | Blog
MongoDB | Blog
B
Blog
N
News and Events Feed by Topic
The Cloudflare Blog
S
Schneier on Security
P
Privacy & Cybersecurity Law Blog
T
The Blog of Author Tim Ferriss
Recorded Future
Recorded Future
Last Week in AI
Last Week in AI
The Last Watchdog
The Last Watchdog
Hacker News - Newest:
Hacker News - Newest: "LLM"
L
LangChain Blog
I
InfoQ
F
Full Disclosure
The Register - Security
The Register - Security
阮一峰的网络日志
阮一峰的网络日志
H
Hacker News: Front Page
V
V2EX

郑文峰的博客

使用dify对接飞书多维表格 使用n8n对接飞书多维表格 服务启动时出现 OOM 一次服务升级时pg表DDL执行超时失败 Go语言高效IO缓冲技术详解 Go语言延迟初始化(Lazy Initialization)最佳实践 Go语言字符串拼接性能对比与优化指南 Go语言结构体内存对齐完全指南 Go语言空结构体:零内存消耗的高效编程 Go语言堆栈分配与逃逸分析深度解析 Go语言原子操作完全指南 Go语言内存预分配完全指南 Go语言零拷贝技术完全指南 Go语言遍历性能深度解析:从原理到优化实践 Go语言Interface Boxing原理与性能优化指南 Go协程池深度解析:原理、实现与最佳实践 使用etcd分布式锁导致的协程泄露与死锁问题 基于pre-commit的Python代码规范落地实践 初识 MCP Server pulsar阻塞导致logstash无法接入日志 django-prometheus使用及源码分析 kube-proxy源码分析 kubernetes service如何通过iptables转发 tcp缓存引起的日志丢失 django-apschedule定时任务异常停止 理解calico容器网络通信方案原理 理解flannel的三种容器网络方案原理 理解Linux IPIP隧道 理解VXLAN网络 理解Linux TunTap设备 快速了解iptables kafka中listener和advertised.listeners的作用 django rest_framework 分页 django后端服务、logstash和flink接入VictoriaMetrics指标监控 python中import原理 docker容器单机网络 手动实现docker容器bridge网络模型 mysql之MVCC原理 mysql之日志 使用java开发logstash的filter插件 使用python实现单例模式的三种方式 redis之缓存 redis之分片集群 redis之哨兵机制 redis之主从库同步 redis之持久化 redis之五种基本数据类型 go中如何处理error pod中将代码与运行环境分离 ddt源码分析 python装饰器的使用方法 读书笔记:如何阅读一本书 使用ddt实现unittest的参数化测试 使用kubeadm安装k8s 优化gin表单的错误提示信息 gin中validator模块的源码分析 go简单使用grpc python简单使用grpc k8s之PV、PVC和StorageClass k8s之StatefulSet k8s之DaemonSet k8s之Job和CronJob k8s之ConfigMap和Secret k8s之Service k8s之Pod k8s之Deployment 容器的本质 docker容器 python迭代器与生成器 python元编程 python垃圾回收机制 python上下文管理器 django rest_framework使用jwt django rest_framework异常处理 django rest_framework 自定义文档 django压缩文件下载 django rest_framework使用pytest单元测试 django restframework choice 自定义输出数据 django Filtering 使用 django viewset 和 Router 配合使用时报的错 django model的序列化 django中使用AbStractUser django.core.exceptions.ImproperlyConfigured Application labels aren't unique, duplicates users django 中 media配置 django 外键引用自身和on_delete参数 django 警告 while time zone support is active Flask使用flask_socketio实现websocket flask结合mongo tornado 文件上传 tornado 使用jwt完成用户异步认证 tornado 用户密码 bcrypt加密 tornado 结合wtforms使用表单操作 tornado finish和write区别 tornado 使用peewee-async 完成异步orm数据库操作 pyspark streaming简介 和 消费 kafka示例 使用hue创建ozzie的pyspark action workflow count的性能优化 django rest_framework Authentication django celery 结合使用 网站
Go语言不可变数据共享:无锁并发编程实践
zhengwenfeng · 2025-06-14 · via 郑文峰的博客

# 前言

对共享数据的并发访问往往需要用到锁,而这是一个常见的性能瓶颈。而不可变数据共享式一种不需要用锁来保护共享数据的方式,创建后的数据永远不改变,这样就不会有竞争问题了。

# 案例一:共享配置

  1. 创建配置结构体
// config.go
type Config struct {
    LogLevel string
    Timeout  time.Duration
    Features map[string]bool // 必须深拷贝,原始map的修改会影响已创建的配置
}

1
2
3
4
5
6

  1. 每次获取配置都是独立的
func NewConfig(logLevel string, timeout time.Duration, features map[string]bool) *Config {
    copiedFeatures := make(map[string]bool, len(features))
    for k, v := range features {
        copiedFeatures[k] = v
    }

    return &Config{
        LogLevel: logLevel,
        Timeout:  timeout,
        Features: copiedFeatures,
    }
}

1
2
3
4
5
6
7
8
9
10
11
12

  1. 使用 atomic.Value 来存储并安全的更新当前配置
var currentConfig atomic.Pointer[Config] // Go 1.19+ 特性

// LoadInitialConfig 初始化配置(必须保证线程安全)
func LoadInitialConfig() {
    cfg := NewConfig("info", 5*time.Second, map[string]bool{"beta": true})
    currentConfig.Store(cfg) // 原子存储初始配置
}

// GetConfig 安全获取当前配置(零锁消耗)
func GetConfig() *Config {
    return currentConfig.Load() // 原子加载指针
}

1
2
3
4
5
6
7
8
9
10
11
12

  1. 在处理程序中使用
func handler(w http.ResponseWriter, r *http.Request) {
    cfg := GetConfig()
    if cfg.Features["beta"] {
        // Enable beta path
    }
    // Use cfg.Timeout, cfg.LogLevel, etc.
}

1
2
3
4
5
6
7

# 案例二:不可变路由表

  1. 创建路由结构体
type Route struct {
    Path    string
    Backend string
}

type RoutingTable struct {
    Routes []Route
}

1
2
3
4
5
6
7
8

  1. 每次获取都是全新版本
func NewRoutingTable(routes []Route) *RoutingTable {
    copied := make([]Route, len(routes))
    copy(copied, routes)
    return &RoutingTable{Routes: copied}
}

1
2
3
4
5

  1. 以原子的方式存储及修改
var currentRoutes atomic.Pointer[RoutingTable]

func LoadInitialRoutes() {
    table := NewRoutingTable([]Route{
        {Path: "/api", Backend: "http://api.internal"},
        {Path: "/admin", Backend: "http://admin.internal"},
    })
    currentRoutes.Store(table)
}

func GetRoutingTable() *RoutingTable {
    return currentRoutes.Load()
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14

  1. 并发路由请求
func routeRequest(path string) string {
    table := GetRoutingTable()
    for _, route := range table.Routes {
        if strings.HasPrefix(path, route.Path) {
            return route.Backend
        }
    }
    return ""
}

1
2
3
4
5
6
7
8
9

# 总结

应用场景

  • 读多写少:配置信息、路由表等低频变更数据
  • 高性能要求:需要避免锁竞争的热点路径

注意事项

  • 深拷贝成本:当数据结构复杂时(嵌套map/slice),需要考虑拷贝性能
  • 内存消耗:每次更新都会创建新对象,需权衡内存与性能
  • 原子性保证:更新操作必须完全替换配置对象,避免部分更新