虽然我已经阅读了所有OP、答案和Why do I get a deadlock when using Tokio with a std::sync::Mutex?的 comments ,但我还不明白为什么OP中的代码永远阻塞.

以下是原始代码的略有更改的版本:

use std::sync::Arc;
use std::sync::Mutex;
// use tokio::sync::Mutex;
use tokio::time::Duration;

async fn f(mtx: Arc<Mutex<i32>>, index: usize) {
    println!("{}: trying to lock...", index);
    {
        let mut v = mtx.lock().unwrap();
        // let mut v = mtx.lock().await;
        println!("{}: locked", index);
        tokio::time::sleep(Duration::from_millis(1)).await;
        *v += 1;
    }
    println!("{}: unlocked", index);
}

#[tokio::main]
async fn main() {
    let mtx = Arc::new(Mutex::new(0));
    tokio::join!(f(mtx.clone(), 1), f(mtx.clone(), 2));
}

输出是

1: trying to lock...
1: locked
2: trying to lock...

(and blocks forever...)

根据答案和 comments (如果我没有看错),原因是the entire code is executed in a single-threaded environment.如果italicized部分是真的,我就能理解屏蔽行为了.然而,我不明白italicized部分是否真的是真的.

据我了解,

  • Tokio的默认运行时是多线程的,除非您显式指定#[tokio::main(flavor = "current_thread")](source)

  • 并且await任务can被自动移动到另一个工作线程(source).

因此,我认为如果任务(即f(mtx.clone(), 1).awaitf(mtx.clone(), 2).awaitsleep(...).await)是chosen(根据Tokio运行时)将在不同线程中执行,代码不会阻塞,但代码looks会阻塞,因为运行时happens Select 任务都在同一个线程中执行.

我的理解正确吗?

推荐答案

整个代码在单线程环境中执行

的确.

Tokio的默认运行时是多线程的

是的,但这只适用于tasks.任务就像轻量级线程,可以在不同的操作系统线程上并行执行.但tokio::join!()不会创建新任务.它是一个Deliverc基元,它接受两个(或更多)future ,并通过状态机将它们组合成一个,执行同一任务.这的优点是它更轻量级,但这也意味着如果您阻止其中一个期货,所有其他期货也将被阻止.因此,它对于真正的IO绑定代码来说是有好处的,如果代码有一点是与PU绑定的,或者您有很多future ,那么最好生成一个任务.

另请注意,Tokio任务may在不同的线程上运行,但这不是guaranteed.特别是,Tokio的优化heuristics可以导致仅使用一个线程.在这种情况下,此代码也将陷入僵局.此外,即使它不会陷入僵局,它仍然处于阻塞状态,并且在spec环境中永远不应该进行阻塞.

Rust相关问答推荐

如何在rust中有条件地分配变量?

关联类型(类型参数)命名约定

交叉术语未正确清除屏幕

访问Rust中的隐藏变量

如何在原始字符串中转义";#和#";

在特征中使用Async时,如何解决不透明类型`impl Future<;out=self>;`不满足其关联的类型边界和警告?

值为可变对象的不可变HashMap

为什么BitVec缺少Serialize trait?

告诉Rust编译器返回值不包含构造函数中提供的引用

在文件链实施中绕过borrow 判断器

什么时候使用FuturesOrdered?

仅发布工作区的二进制 crate

Rust LinkedList 中的borrow 判断器错误的原因是什么?

Rust 中多个 & 符号的内存表示

如何使用 Bincode 在 Rust 中序列化 Enum,同时保留 Enum 判别式而不是索引?

从 Axum IntoResponse 获取请求标头

判断对象是 PyDatetime 还是 Pydate 的实例?

在单独的线程上运行 actix web 服务器

提取 struct 生成宏中字段出现的索引

为什么 `ref` 会导致此示例*取消引用*一个字段?