use bencher::{black_box, Bencher}; use std::sync::Arc; use tokio::{sync::RwLock, task}; fn read_uncontended(b: &mut Bencher) { let rt = tokio::runtime::Builder::new_multi_thread() .worker_threads(6) .build() .unwrap(); let lock = Arc::new(RwLock::new(())); b.iter(|| { let lock = lock.clone(); rt.block_on(async move { for _ in 0..6 { let read = lock.read().await; black_box(read); } }) }); } fn read_concurrent_uncontended_multi(b: &mut Bencher) { let rt = tokio::runtime::Builder::new_multi_thread() .worker_threads(6) .build() .unwrap(); async fn task(lock: Arc>) { let read = lock.read().await; black_box(read); } let lock = Arc::new(RwLock::new(())); b.iter(|| { let lock = lock.clone(); rt.block_on(async move { let j = tokio::try_join! { task::spawn(task(lock.clone())), task::spawn(task(lock.clone())), task::spawn(task(lock.clone())), task::spawn(task(lock.clone())), task::spawn(task(lock.clone())), task::spawn(task(lock.clone())) }; j.unwrap(); }) }); } fn read_concurrent_uncontended(b: &mut Bencher) { let rt = tokio::runtime::Builder::new_current_thread() .build() .unwrap(); async fn task(lock: Arc>) { let read = lock.read().await; black_box(read); } let lock = Arc::new(RwLock::new(())); b.iter(|| { let lock = lock.clone(); rt.block_on(async move { tokio::join! { task(lock.clone()), task(lock.clone()), task(lock.clone()), task(lock.clone()), task(lock.clone()), task(lock.clone()) }; }) }); } fn read_concurrent_contended_multi(b: &mut Bencher) { let rt = tokio::runtime::Builder::new_multi_thread() .worker_threads(6) .build() .unwrap(); async fn task(lock: Arc>) { let read = lock.read().await; black_box(read); } let lock = Arc::new(RwLock::new(())); b.iter(|| { let lock = lock.clone(); rt.block_on(async move { let write = lock.write().await; let j = tokio::try_join! { async move { drop(write); Ok(()) }, task::spawn(task(lock.clone())), task::spawn(task(lock.clone())), task::spawn(task(lock.clone())), task::spawn(task(lock.clone())), task::spawn(task(lock.clone())), }; j.unwrap(); }) }); } fn read_concurrent_contended(b: &mut Bencher) { let rt = tokio::runtime::Builder::new_current_thread() .build() .unwrap(); async fn task(lock: Arc>) { let read = lock.read().await; black_box(read); } let lock = Arc::new(RwLock::new(())); b.iter(|| { let lock = lock.clone(); rt.block_on(async move { let write = lock.write().await; tokio::join! { async move { drop(write) }, task(lock.clone()), task(lock.clone()), task(lock.clone()), task(lock.clone()), task(lock.clone()), }; }) }); } bencher::benchmark_group!( sync_rwlock, read_uncontended, read_concurrent_uncontended, read_concurrent_uncontended_multi, read_concurrent_contended, read_concurrent_contended_multi ); bencher::benchmark_main!(sync_rwlock);