You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Actix中不使用Mutex修改结构体?(多线程读写场景)

解决Actix框架下多读少写的共享数据更新问题

你的场景是多个请求线程频繁读取共享数据,另有线程每日更新一次数据,允许读取到旧数据,只需保证内存数据最终能完成更新。当前代码的问题在于web::Data<MyStruct>仅提供不可变共享访问,无法在set接口中修改数据,需要借助内部可变性容器来实现线程安全的读写操作。

针对多读少写的场景,推荐使用Arc<RwLock<MyStruct>>:Arc提供线程间的共享所有权,RwLock支持多线程同时读,同一时间仅允许一个线程写,完美匹配你的需求。

修改后的完整代码

use serde::Serialize;
use actix_web::{HttpServer, Responder, get, post, App, HttpResponse, web};
use std::sync::{Arc, RwLock};

#[derive(Serialize, Default)]
struct MyStruct {
    a: String,
    b: Vec<String>,
}

#[get("/get")]
async fn get(data: web::Data<Arc<RwLock<MyStruct>>>) -> impl Responder {
    // 获取读锁,允许多个线程同时读取
    let data_read = data.read().unwrap();
    HttpResponse::Ok().json(&data_read)
}

// 改用POST方法更符合语义(修改资源)
#[post("/set")]
async fn set(data: web::Data<Arc<RwLock<MyStruct>>>) -> impl Responder {
    // 获取写锁,同一时间仅一个线程能修改
    let mut data_write = data.write().unwrap();
    // 示例修改逻辑:更新a和b的值
    data_write.a = "更新后的字符串".to_string();
    data_write.b = vec!["新元素1".to_string(), "新元素2".to_string()];
    
    HttpResponse::Ok().body("数据更新完成")
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    // 创建带内部可变性的共享数据
    let shared_data = Arc::new(RwLock::new(MyStruct::default()));
    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(shared_data.clone()))
            .service(get)
            .service(set)
    }).bind(("0.0.0.0", 8080))?
    .run()
    .await
}

关键说明

  • 线程安全保障:Arc让数据能被多个线程共享,RwLock确保读操作并发安全、写操作互斥安全,完全适配Actix多线程工作模式。
  • 读写锁特性:读锁read()不会阻塞其他读请求,仅会阻塞写请求;写锁write()会阻塞所有读和写请求,适合你每日一次低频率写的场景。
  • 错误处理:示例中用unwrap()简化处理,生产环境建议根据业务需求处理锁可能的poisoned状态(比如锁持有线程panic导致锁中毒)。
  • 接口语义优化:把set接口改为POST方法,更符合HTTP修改资源的语义规范。

内容的提问来源于stack exchange,提问作者julien

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 11:52:44