🎃
tokioでタスクをたくさん作って待つ(ド級初心者)
永遠の初級者を自覚しています。
最近なんでかんでも、asyncやらawaitで非同期プログラミングを意識させられます。
それはそれとして、Rustでたくさんタスク(スレッド?)を作って非同期で実行させるのはどうするのか?
みたいなド級初心者的な疑問があり、なんとなく作ってみました。
やりたいこと
- 非同期ランタイムとしてはTokioを使用する
- async fn で作った非同期関数をたくさん同時に実行する。
- それがわかるようにする
ソースコード
試行錯誤のうえこんなんなりました。
cargo.toml
[package]
name = "rust-multi-thread01"
version = "0.1.0"
authors = ["HOGEHOGE <hogehoge@example.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.40"
dotenv = "0.15.0"
futures = "0.3.15"
rand = "0.8.3"
tokio = { version = "1.4.0", features = ["full"] }
main.rs
use anyhow::Error;
use futures::future;
use std::time::Duration;
use tokio::time::sleep;
#[tokio::main]
async fn main() {
let mut tasks = Vec::new();
for no in 1..=10 {
let x = tokio::spawn(test01(no));
tasks.push(x);
}
sleep(Duration::from_millis(1000)).await;
// tasks.into_iter().for_each(|t| { let _ = tokio::runtime::Handle::current().block_on(t); });
println!("=======================");
let x = future::join_all(tasks.into_iter()).await;
println!("------------------------");
}
async fn test01(no: i32) -> Result<(), Error> {
// 待つ時間計算
let r = rand::random::<u32>() as u64;
let max = std::u32::MAX as u64;
let wait = r * 5000 / max;
println!("{}:start", no);
sleep(Duration::from_millis(wait as u64)).await;
println!("{}:end", no);
Ok(())
}
適当な解説
test01 関数でやっていること
開始時にstart、終了時にendを出力。そして処理の本題は最大5秒までランダムで待つ。
タスクの開始
tokio::spawn に 非同期の関数を渡すだけ。そうするとJoinHandleとかいうものが帰ってきます。
JoinHandleをVecに保存しておき後で使います。
タスクの終了を待つ
future::join_all に イテレーターで JoinHandle 渡してやるといいよ、って何処かで書いてあったのでそうしました。最後に .await 入れて待つのを忘れないように。
あと
tasks.into_iter().for_each(|t| { let _ = tokio::runtime::Handle::current().block_on(t); })
こっちでも同じようなことができました。まぁ join_all の方がすっきりしてよいのでは~?と思っています。
tokio::spawn 直後から処理が動いているか確認する
main関数内で sleep(Duration::from_millis(1000)).await; を入れていますが、spawn されてそのまま非同期の関数が実行されるなら、=======================が表示される前にstartの表示がされるはずです。
出力結果
なんかいい感じにできました(´▽`)
6:start
5:start
7:start
2:start
4:start
8:start
1:start
3:start
10:start
9:start
2:end
5:end
7:end
8:end
=======================
10:end
4:end
6:end
3:end
1:end
9:end
------------------------
Discussion