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

为何Rc可在异步函数中运行?线程安全相关技术疑问

问题解答

你的代码不会引发线程安全问题,原因如下:

  1. Rc的线程安全限制本质
    Rc用普通整数实现引用计数,没有原子操作保护,跨线程并发修改(clone或drop)会导致数据竞争,因此Rc默认不实现Send trait——这意味着持有Rc的任务无法被安全地在多个线程间转移。

  2. Tokio调度器的适配逻辑
    虽然#[tokio::main]默认是多线程运行时,但Tokio会自动识别任务是否实现Send:

  • 对于!Send的任务(比如你的test函数返回的Future,它在await期间持有Rc),Tokio会将其固定在单个线程上执行,不会调度到其他线程。因此Rc的引用计数始终在同一个线程内被修改,不会出现跨线程的数据竞争。
  1. 代码能编译的原因
    Tokio并没有强制要求所有任务必须是Send,它支持运行非Send任务,只是会限制这类任务的执行范围,确保符合安全规则。

额外建议

  • 如果你确实需要在多线程间共享引用计数对象,应该用std::sync::Arc(原子引用计数),它的引用计数操作是线程安全的,实现了Send和Sync trait。
  • 代码中混用了Tokio和async_std的sleep,虽然能运行,但建议统一使用Tokio的tokio::time::sleep,避免运行时兼容性问题。

修改后的线程安全示例(用Arc替代Rc):

use std::sync::Arc;
use tokio::join;
use tokio::time::{sleep, Duration};

async fn test(t: Arc<String>) {
    let k = t;
    println!("1. test,{:?}", k);
    sleep(Duration::from_secs(1)).await;
    println!("2. test,{:?}", k);
}

#[tokio::main]
async fn main() {
    let r = Arc::new("abc".to_string());
    let f1 = test(r.clone());
    let f2 = test(r.clone());
    join!(f1, f2);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 04:45:35