let log = Arc::new(Mutex::new(LogFile::open("./tab-seg-1").unwrap()));
// ------------------------------------------------
let now = Instant::now();
// ============================================
for elem in 0..10_000 {
let ilog = log.clone();
tokio::task::spawn_blocking(move || {
let mut log = ilog.lock().unwrap();
if let Err(e) = log.write(&mut object_factory()) {
panic!("{}", e);
}
let _ = log.flush();
});
}
// ============================================
let nnow = Instant::now();
println!("==> {:?}", nnow.duration_since(now));
block_in_place code :
let mut log = LogFile::open("./tab-seg-1").unwrap();
// ------------------------------------------------
let now = Instant::now();
// ============================================
for elem in 0..10_000 {
tokio::task::block_in_place(|| {
if let Err(e) = log.write(&mut object_factory()) {
panic!("{}", e);
}
let _ = log.flush();
});
}
// ============================================
let nnow = Instant::now();
println!("==> {:?}", nnow.duration_since(now));
There are many reasons to prefer spawn_blocking. In the area of performance reasons, well, block_in_place can cause other tasks to get moved between threads a lot more, which can hurt the performance of those other tasks.
There are also some correctness challenges:
You cannot really use block_in_place inside a task that uses within-task concurrency such as tokio::join!, tokio::select!, join_all, FuturesUnordered, StreamExt::buffer_unordered and so on.
You cannot use block_in_place inside a current thread runtime or LocalSet.