Dart-Async/Awaitをちょっと調査

Dartの非同期処理のうちAsync/Awaitのサンプルを作ったところ、想定通りにAsyncメソッドが動かなかったのでちょっと調べてみた。

Dartのドキュメントを見てもこれに関して直接的な解説はなかったのだけど、検索してみると2014年頃にはどうやら既知の内容だった。
他の言語のAsync/Awaitもおんなじ感じなんだろうか。

うまく動かないサンプル

test関数内で2秒後にhogeを出力してストップウォッチを止める。
メイン側は、定期的にストップウォッチの経過時間を表示するもの。

void main(List<String> arguments) async {
  final timer = Stopwatch();
  test(timer);
  timer.start();
  for (int i = 0;; i++) {
    if ((i % 100000000) == 0) {
      print("${timer.elapsed}");
    }
  }
}

void test(Stopwatch timer) async {
  await Future.delayed(const Duration(seconds: 2));
  print("hoge");
  timer.stop();
}

これを実行すると以下の様になる。

0:00:00.000287
0:00:00.345996
0:00:00.648783
中略
0:00:01.930432
0:00:02.241629
0:00:02.554350
0:00:02.868779
0:00:03.203732
略

2秒を経過してもtest側の後の処理がされていない。
つまりFuture.delayedから処理が抜けていないのだ。

とりあえず動いたサンプル

サンプル1に対してタイマーの経過時間を表示するタイミングでawaitコードを入れてみた。

void main(List<String> arguments) async {
  final timer = Stopwatch();
  test(timer);
  timer.start();
  for (int i = 0;; i++) {
    if ((i % 100000000) == 0) {
      print("${timer.elapsed}");
      await Future.delayed(const Duration(microseconds: 1));
    }
  }
}

void test(Stopwatch timer) async {
  await Future.delayed(const Duration(seconds: 2));
  print("hoge");
  timer.stop();
}

この結果は、以下の様になる。

0:00:00.000283
0:00:00.702220
0:00:01.494513
0:00:02.166780
hoge
0:00:02.167137

一応2秒をちょっと経過した時点でtestのawait以降の処理が行われた。

上の例では2秒から0.16秒ほど遅れているが、経過時間を表示する処理部分のカウンター値を少なくすることで2秒からの遅れは少なくなる。

結果

DartのプログラムはIsolateを使わない限り1プロセス1スレッドで動作する。
これはhttps://dart.dev/guides/language/language-tour内のIsolatesにそれとなく書かれている。

Instead of threads, all Dart code runs inside of isolates. Each Dart isolate has a single thread of execution and shares no mutable objects with other isolates.

1スレッド内で非同期処理を行うため、awaitでasyncコードのコンテキストスイッチが行われているようだった。

Flutterアプリケーションであれば、画面のデータ待ち部分ではAwaitで待ち状態になっているのであまり気にならないのだけどDartのコンソールアプリケーションでは、Asyncを使う場合適当にAwaitを使っておかないとAsyncなメソッドが正しく動作しないということになるのだろう。

なお、もし重く長い処理を個別に動かそうとするのであれば、Isolateを使わないと無駄にパフォーマンスダウンになるのだろう。
この場合、呼び出し側とIsolate側で情報を直接共有することができないので、Streamやファイルで情報共有するしかないので、データのやり取りに関してはちょっと面倒かもしれない。

コメント

タイトルとURLをコピーしました