当使用Tokio时,我遇到了死锁条件:
use tokio::time::{delay_for, Duration};
use std::sync::Mutex;
#[tokio::main]
async fn main() {
let mtx = Mutex::new(0);
tokio::join!(work(&mtx), work(&mtx));
println!("{}", *mtx.lock().unwrap());
}
async fn work(mtx: &Mutex<i32>) {
println!("lock");
{
let mut v = mtx.lock().unwrap();
println!("locked");
// slow redis network request
delay_for(Duration::from_millis(100)).await;
*v += 1;
}
println!("unlock")
}
产生以下输出,然后永远挂起。
lock
locked
lock
根据Tokio文档,在异步代码中使用
std::sync::Mutex
是可以的。与普遍观点相反,通常情况下应使用标准库中的普通Mutex。然而将
Mutex
替换为tokio::sync::Mutex
不会触发死锁,并且一切正常“按预期”运行,但仅适用于上述示例情况。在真实场景中,如果延迟由某个Redis请求引起,则仍会失败。我认为这可能是因为我根本没有生成线程,因此,即使是“并行”执行,由于await只是暂停执行,所以会在同一线程上锁定。
在不生成单独线程的情况下,如何以Rust语言方式实现我想要的效果?