news 2026/8/11 10:23:44

rust一个cfgservice共享

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
rust一个cfgservice共享

在 Rust 中实现一个共享配置服务(ConfigService),需要考虑线程安全、生命周期和性能。以下是几种常见方案:


方案一:Arc + RwLock(推荐:读多写少)

rust

use std::sync::{Arc, RwLock}; use std::collections::HashMap; #[derive(Clone, Debug)] pub struct Config { pub db_url: String, pub port: u16, pub features: HashMap<String, bool>, } pub struct ConfigService { config: Arc<RwLock<Config>>, } impl ConfigService { pub fn new(config: Config) -> Self { Self { config: Arc::new(RwLock::new(config)), } } // 获取配置快照(克隆,适合配置较小) pub fn get(&self) -> Config { self.config.read().unwrap().clone() } // 读取单个字段 pub fn get_port(&self) -> u16 { self.config.read().unwrap().port } // 更新配置 pub fn update<F>(&self, f: F) where F: FnOnce(&mut Config), { let mut cfg = self.config.write().unwrap(); f(&mut cfg); } } // 克隆 ConfigService 是轻量的(Arc 只增加引用计数) impl Clone for ConfigService { fn clone(&self) -> Self { Self { config: Arc::clone(&self.config), } } }

使用:

rust

fn main() { let cfg = Config { db_url: "postgres://localhost".to_string(), port: 8080, features: HashMap::new(), }; let service = ConfigService::new(cfg); let service2 = service.clone(); // 共享同一个配置 // 读取 println!("port: {}", service.get_port()); // 更新 service.update(|c| c.port = 9090); println!("new port: {}", service2.get_port()); // 9090 }

方案二:ArcSwap(高性能,适合频繁读、极少写)

rust

use arc_swap::ArcSwap; use std::sync::Arc; pub struct ConfigService { config: ArcSwap<Config>, } impl ConfigService { pub fn new(config: Config) -> Self { Self { config: ArcSwap::new(Arc::new(config)), } } // 读无锁,性能极高 pub fn get(&self) -> Arc<Config> { self.config.load().clone() // 原子操作,无锁 } // 原子替换整个配置 pub fn update(&self, new_config: Config) { self.config.store(Arc::new(new_config)); } }

依赖:

toml

[dependencies] arc-swap = "1.7"

表格

方案读性能写性能适用场景
RwLock有锁竞争有锁读写均衡
ArcSwap无锁原子替换读多写极少(推荐)

方案三:静态全局 + OnceLock(全局单例)

rust

use std::sync::OnceLock; use std::sync::{Arc, RwLock}; static CONFIG: OnceLock<Arc<RwLock<Config>>> = OnceLock::new(); pub fn init_config(cfg: Config) { CONFIG.set(Arc::new(RwLock::new(cfg))).unwrap(); } pub fn config() -> Arc<RwLock<Config>> { CONFIG.get().expect("Config not initialized").clone() } // 使用 fn main() { init_config(Config { /* ... */ }); let cfg = config(); println!("{}", cfg.read().unwrap().port); }

方案四:使用configcrate(生产级)

toml

[dependencies] config = "0.14" serde = { version = "1", features = ["derive"] } lazy_static = "1.4"

rust

use config::{Config, ConfigError, Environment, File}; use serde::Deserialize; use std::sync::{Arc, RwLock}; #[derive(Debug, Deserialize, Clone)] pub struct Settings { pub debug: bool, pub database: Database, } #[derive(Debug, Deserialize, Clone)] pub struct Database { pub url: String, pub pool_size: u32, } pub struct ConfigService { settings: Arc<RwLock<Settings>>, } impl ConfigService { pub fn new() -> Result<Self, ConfigError> { let s = Config::builder() .add_source(File::with_name("config/default")) .add_source(File::with_name("config/local").required(false)) .add_source(Environment::with_prefix("APP")) .build()?; Ok(Self { settings: Arc::new(RwLock::new(s.try_deserialize()?)), }) } pub fn get(&self) -> Settings { self.settings.read().unwrap().clone() } pub fn reload(&self) -> Result<(), ConfigError> { let new = Self::new()?; *self.settings.write().unwrap() = new.get(); Ok(()) } }

方案对比与选择

表格

场景推荐方案
简单共享、读多写少Arc<RwLock<Config>>
极高并发读、配置几乎不变ArcSwap
全局唯一、启动初始化OnceLock/lazy_static
生产环境、热重载、多来源configcrate +ArcSwap

完整生产示例(ArcSwap + 热重载)

rust

use arc_swap::ArcSwap; use notify::{Config as NotifyConfig, Event, RecommendedWatcher, RecursiveMode, Watcher}; use std::path::Path; use std::sync::Arc; pub struct ConfigService { inner: ArcSwap<Config>, _watcher: RecommendedWatcher, // 保持 watcher 存活 } impl ConfigService { pub fn load<P: AsRef<Path>>(path: P) -> anyhow::Result<Self> { let config = Arc::new(Self::parse(&path)?); let swap = ArcSwap::new(Arc::clone(&config)); let swap_clone = Arc::clone(&swap); let path = path.as_ref().to_owned(); let mut watcher = RecommendedWatcher::new( move |res: Result<Event, _>| { if let Ok(event) = res { if event.kind.is_modify() { if let Ok(new_cfg) = Self::parse(&path) { swap_clone.store(Arc::new(new_cfg)); println!("Config reloaded"); } } } }, NotifyConfig::default(), )?; watcher.watch(path.as_ref(), RecursiveMode::NonRecursive)?; Ok(Self { inner: swap, _watcher: watcher, }) } pub fn get(&self) -> Arc<Config> { self.inner.load().clone() } fn parse<P: AsRef<Path>>(path: P) -> anyhow::Result<Config> { let content = std::fs::read_to_string(path)?; Ok(toml::from_str(&content)?) } }

核心原则:配置服务本质是多线程共享只读数据 + 偶尔原子更新ArcSwap是 Rust 生态中最高效的方案。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/11 10:22:57

30分钟掌握数组计数算法:哈希映射与计数排序优化

1. 项目概述&#xff1a;30分钟掌握数组计数算法精髓 数组计数是算法领域最基础却最常被轻视的核心技能。我在处理电商平台千万级订单数据时发现&#xff0c;90%的初级工程师的算法瓶颈都源于对数组计数原理理解不透彻。这个30分钟速成方法提炼自ACM竞赛选手的实战技巧&#xf…

作者头像 李华
网站建设 2026/8/11 10:22:26

什么是底线检测器?一文搞懂梭芯底线在线监测

如果你负责工业缝纫、模板缝制或纺织设备的产线&#xff0c;大概率遇到过这种场面&#xff1a;机器还在转&#xff0c;操作工却没发现梭芯底线已经快空了&#xff0c;或者某根线在中途断了——直到一批活儿缝完质检&#xff0c;才发现整批跳针、浮线&#xff0c;只能返工。&quo…

作者头像 李华
网站建设 2026/8/11 10:22:09

从AI笔记到知识网络:Brain KIT如何用LLM构建可计算知识库

上周&#xff0c;我尝试用一个大语言模型帮我整理一份关于“向量数据库选型”的笔记。我给了它几篇技术文章、一些官方文档片段和我的零散想法。模型确实生成了结构化的内容&#xff0c;但当我第二天想基于这份笔记继续深入时&#xff0c;问题来了&#xff1a;我记不清它引用了…

作者头像 李华
网站建设 2026/8/11 10:18:34

鸣潮自动化终极指南:ok-ww如何用AI图像识别解放你的游戏时间

鸣潮自动化终极指南&#xff1a;ok-ww如何用AI图像识别解放你的游戏时间 【免费下载链接】ok-wuthering-waves 鸣潮 后台自动战斗 自动刷声骸 一键日常 Automation for Wuthering Waves 项目地址: https://gitcode.com/GitHub_Trending/ok/ok-wuthering-waves ok-ww是一…

作者头像 李华