ついに正式対応されるRustのawait/asyncを1.39betaで確認してみた
※こちらにも同じ内容を書いています
2019年11月リリース予定のRust1.39でついにawait/asyncが正式対応となります。ここにたどり着くまでに色々な紆余曲折があったようです。
1.待機にawaitを使わない場合
ソースコード
内容としてはファンクションを二つ用意して、中で10回ループ、ループごとに500msスリープを入れるという流れです。これをspawnで実行し、全ての処理が終了するまで待ちます。
このコードでは通常のスレッド用Sleepを使って待機を行っています。
Test02.rs
#![allow(non_snake_case)]
use std::{thread, time};
async fn foo1() {
for i in 0..10 {
std::thread::sleep(time::Duration::from_millis(500));
println!("foo1:{} Thread[{:?}]", i, thread::current().id());
}
}
async fn foo2() {
for i in 0..10 {
std::thread::sleep(time::Duration::from_millis(500));
println!("foo2:{} Thread[{:?}]", i, thread::current().id());
}
}
#[runtime::main]
async fn main() {
let handles = &mut [runtime::spawn(foo1()), runtime::spawn(foo2())];
for handle in handles {
handle.await;
}
}
実行結果
ThreadIdに特徴が現れていますが、完全にマルチスレッドの動きです。スレッドは切り替わらずに、単純にSleepに入っているのが分かります。
foo2:0 Thread[ThreadId(2)]
foo1:0 Thread[ThreadId(3)]
foo1:1 Thread[ThreadId(3)]
foo2:1 Thread[ThreadId(2)]
foo2:2 Thread[ThreadId(2)]
foo1:2 Thread[ThreadId(3)]
foo1:3 Thread[ThreadId(3)]
foo2:3 Thread[ThreadId(2)]
foo1:4 Thread[ThreadId(3)]
foo2:4 Thread[ThreadId(2)]
foo2:5 Thread[ThreadId(2)]
foo1:5 Thread[ThreadId(3)]
foo1:6 Thread[ThreadId(3)]
foo2:6 Thread[ThreadId(2)]
foo1:7 Thread[ThreadId(3)]
foo2:7 Thread[ThreadId(2)]
foo1:8 Thread[ThreadId(3)]
foo2:8 Thread[ThreadId(2)]
foo2:9 Thread[ThreadId(2)]
foo1:9 Thread[ThreadId(3)]
2.awaitを使用した場合
ソースコード
ここではawait対応のSleepを使っています。
Test01.rs
#![allow(non_snake_case)]
use runtime::time::Delay;
use std::{thread, time};
async fn foo1() {
for i in 0..10 {
Delay::new(time::Duration::from_millis(500)).await;
println!("foo1:{} Thread[{:?}]", i, thread::current().id());
}
}
async fn foo2() {
for i in 0..10 {
Delay::new(time::Duration::from_millis(500)).await;
println!("foo2:{} Thread[{:?}]", i, thread::current().id());
}
}
#[runtime::main]
async fn main() {
let handles = &mut [runtime::spawn(foo1()), runtime::spawn(foo2())];
for handle in handles {
handle.await;
}
}
実行結果
実行結果を見ると、スリープのawait待機でスレッドが切り替わっているのが分かります。どうやらasync/awaitの非同期処理は、スレッドそのものをいったん止めることで実現しているようです。
foo2:0 Thread[ThreadId(4)]
foo1:0 Thread[ThreadId(5)]
foo2:1 Thread[ThreadId(7)]
foo1:1 Thread[ThreadId(9)]
foo1:2 Thread[ThreadId(3)]
foo2:2 Thread[ThreadId(15)]
foo2:3 Thread[ThreadId(16)]
foo1:3 Thread[ThreadId(2)]
foo1:4 Thread[ThreadId(8)]
foo2:4 Thread[ThreadId(12)]
foo1:5 Thread[ThreadId(13)]
foo2:5 Thread[ThreadId(14)]
foo1:6 Thread[ThreadId(10)]
foo2:6 Thread[ThreadId(11)]
foo2:7 Thread[ThreadId(6)]
foo1:7 Thread[ThreadId(17)]
foo2:8 Thread[ThreadId(4)]
foo1:8 Thread[ThreadId(5)]
foo2:9 Thread[ThreadId(7)]
foo1:9 Thread[ThreadId(9)]
3.まとめ
Rustがawait/asyncに対応することによって、通信やDB系の処理を書くときの利便性が向上が期待できます。今後、await/asyncを前提に対応がすすめられた便利なパッケージが増えれば、Rustの普及に弾みが付くかもしれません。