0

ついに正式対応されるRustのawait/asyncを1.39betaで確認してみた

ついに正式対応される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の普及に弾みが付くかもしれません。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away