webrtc
webrtc copied to clipboard
[All] Mutex performance improvement: asynchronous mutex vs synchronous mutex
tokio::sync::Mutex vs std::sync::Mutex vs parking_lot::Mutex
change tokio::sync::Mutex to std::sync::Mutex or parking_lot::Mutex when it is not across .await
For example, don't use std::sync::Mutex or parking_lot::Mutex on the following case, which hold the lock across the .await point.
async fn work(mtx: &Mutex<i32>) {
println!("lock");
{
let mut v = mtx.lock().unwrap();
println!("locked");
// synchronous Mutex lock across .await point will cause deadlock,
// for this case, use asynchronous Mutex
delay_for(Duration::from_millis(100)).await;
*v += 1;
}
println!("unlock")
}
it is ok to use std::sync::Mutex or parking_lot::Mutex when it is not across the .await point, for example:
async fn work(mtx: &Mutex<i32>) {
println!("lock");
{
let mut v = mtx.lock().unwrap();
println!("locked");
*v += 1;
}
println!("unlock")
}
it is ok to use std::sync::Mutex or parking_lot::Mutex when it is not across the .await point, for example:
It also kinda depends on what thread is being locked. Locking runtime's (tokio/async-std) threads might result in whole system performance degradation, since locking runtime's threads would prevent them from driving other tasks (like i/o) or even disrupt the whole cooperative scheduling. Blocking operations are usually offloaded on a separate threads (spawn_blocking)
@alexlapa
Tokio's docs recommend using std::sync::Mutex
or parking_lot::Mutex
Note, std::sync::Mutex and not tokio::sync::Mutex is used to guard the HashMap. A common error is to unconditionally use tokio::sync::Mutex from within async code. An async mutex is a mutex that is locked across calls to .await.
A synchronous mutex will block the current thread when waiting to acquire the lock. This, in turn, will block other tasks from processing. However, switching to tokio::sync::Mutex usually does not help as the asynchronous mutex uses a synchronous mutex internally.
As a rule of thumb, using a synchronous mutex from within asynchronous code is fine as long as contention remains low and the lock is not held across calls to .await. Additionally, consider using parking_lot::Mutex as a faster alternative to std::sync::Mutex.