一个“async”互斥锁与一个“普通”的互斥锁有何不同?我认为这就是tokio的
Mutex
和普通的std lib Mutex
之间的区别。但是,从概念上讲,我不明白互斥锁怎么可能是“async”的。难道不是只有一个东西可以同时使用它吗?Mutex
和普通的std lib Mutex
之间的区别。但是,从概念上讲,我不明白互斥锁怎么可能是“async”的。难道不是只有一个东西可以同时使用它吗?let mtx = std::sync::Mutex::new(0);
let _guard = mtx.lock().unwrap();
let mtx = tokio::sync::Mutex::new(0);
let _guard = mtx.lock().await;
Future
并且设计用于 async
/await
上下文中使用。async
/await
上下文中阻塞应该尽量避免。因此,只有在不期望阻塞时才使用同步互斥锁。以下是需要记住的一些情况:.await
调用期间持有锁,请使用异步互斥锁。当使用线程安全的 futures 时,编译器通常会拒绝此操作,因为大多数同步互斥锁不能发送到另一个线程。
- 如果您的锁是有争议的(即,如果您希望在需要时已经锁定互斥锁),则应使用异步互斥锁。这可能发生在将多个任务同步到池或有界队列中时。
- 如果您有复杂和/或计算密集型的更新,那么这些更新可能应该移动到阻塞池中,在那里您将使用同步互斥锁。println!
需要锁定一个互斥锁吗?这些互斥锁的用途可以是同步的,即使在异步上下文中也可以使用。即使锁定会阻塞,它通常也不会比进程上下文切换更有影响,而这种切换总是会发生的。Mutex
具有 .blocking_lock()
方法,如果需要两种锁定行为,则此方法非常有用。因此,互斥锁可以是同步和异步的!
.await
跨越同步锁,但许多异步框架默认需要线程安全的任务,并且标准的Mutex
的锁保护不是线程安全的,所以你经常会遇到问题。如果你想要,可以使用Mutex
,因为它的保护是线程安全的。 - kmdreko.await
上持有锁时,你应该考虑使用异步锁的原因并不是由于线程安全问题,而是因为在.await
期间任务被挂起(因此锁被持有)的时间是不可预测的(通常是由于I/O)。因此,在异步上下文中的其他地方获取锁时,你知道它可能会被持有很长时间,所以你需要使用异步互斥锁来避免阻塞执行器。如果不这样做,甚至可能会陷入死锁(取决于执行器的工作窃取行为)。 - kmdreko