このスライドは理論的な厳密さよりはわかりやすさと勢いを意識しています
今回実装しているB-Tree自体まだ完璧ではない
同じことをやっておられた方が先にいた
「RustでOn-diskなB+Treeを作ったときの細かな話」 By KOBA789
#[tokio::main(worker_threads = 1)]
async fn main() -> Result<(), Box> {
// ノンブロッキングタスク
let non_blocking_task = tokio::task::spawn(async {
println!("Hello from non-blocking task");
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
println!("Bye from non-blocking task");
});
// ブロッキングタスク
let blocking_task = tokio::task::spawn(async {
println!("Hello from blocking task");
std::thread::sleep(std::time::Duration::from_secs(5));
println!("Bye from blocking task");
});
// どちらも終わるのを待つ
non_blocking_task.await?;
blocking_task.await?;
Ok(())
}
Hello from non-blocking task
Hello from blocking task
Bye from blocking task
Bye from non-blocking task
速く終わるはずのタスクが遅く終わる
基本的にはtokioのノンブロッキングなAPIを使えば問題はないけど、
CPUの消費が激しいタスクやブロッキングタスクを実行するときはこれでいい
let blocking_task = tokio::task::spawn_blocking(|| {
println!("Hello from blocking task");
std::thread::sleep(std::time::Duration::from_secs(5));
println!("Bye from blocking task");
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
// Arcで包んだMutexでカウンタを作成
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
// 各スレッドにカウンタのクローンを渡す
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
// 全てのスレッドの終了を待つ
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
// std::sync
pub struct MutexGuard<'a, T: ?Sized + 'a>
std::sync::Mutex<T>なやつからlock().unwrap()で取れるやつ
MutexGuard<'a, T>: ライフタイムパラメータ 'a を持つ。
Mutexがスコープから外れるとMutexGuardも解放される
// tokio::sync
pub struct OwnedMutexGuard<T: ?Sized>
tokio::async::Mutex<T>なやつからlock().awaitで取れるやつ
OwnedMutexGuard<T>: ライフタイムパラメータがない。
所有権に基づいて動作し、非同期コンテキストで使用される