LoginSignup
3
1

More than 3 years have passed since last update.

Dart(Flutter)の非同期周り(compute)

Posted at

Dartの非同期周り(async, await, then)でシングルスレッドでの非同期の挙動を調査したので、マルチスレッドでの非同期の挙動を確認。
DartではIsolateという仕組みでマルチスレッドを実現出来る。
FlutterではIsolateをラップしたcomputeライブラリで簡単に利用出来るのでそちらでの挙動を確認。

動作検証

async thenの場合

async.dart
void main() async {
  print("${DateTime.now()}: 001");

  returnTwo().then((value) {
    print(value);
  });

  print("${DateTime.now()}: 003");
}

Future<String> returnTwo() async {
  print("${DateTime.now()}: returnTwo");
  await Future.delayed(Duration(seconds: 2));
  return "${DateTime.now()}: 002";
}
2020-10-14 16:15:17.068856: 001
2020-10-14 16:15:17.072159: returnTwo
2020-10-14 16:15:17.075668: 003
2020-10-14 16:15:19.080595: 002

これはおさらい。
2秒の待ちが002と003の間にあるのがポイント。

重い処理の場合

Dartのイベントループはいい感じにシングルスレッドで非同期処理を実現しているが、とはいえ重い処理がアプリ上にある場合には当然スレッドを専有してしまう。
それをWhileループで再現してみる。

while.dart
void main() async {
  print("${DateTime.now()}: 001");

  returnTwo().then((value) {
    print(value);
  });

  print("${DateTime.now()}: 003");
}

// 厳密にはFutureでも無い
Future<String> returnTwo() async {
  print("${DateTime.now()}: returnTwo");

  int beforeLoop = DateTime.now().millisecondsSinceEpoch;
  while(true) {
    int nowLoop = DateTime.now().millisecondsSinceEpoch;
    if ((beforeLoop + 2000) <= nowLoop) {
      break;
    }
  }

  return "${DateTime.now()}: 002";
}
2020-10-14 16:23:11.857362: 001
2020-10-14 16:23:11.860570: returnTwo
2020-10-14 16:23:13.861902: 003
2020-10-14 16:23:13.860: 002

2秒の待ちが発生しているのが、returnTwoと003の間である。
returnTwo()内部で重い処理があるとこのようにスレッドが専有される。
UIを持つアプリであれば当然その間はUIの描画は停止し、ユーザーからのラップなどのイベントの受付も動作しなくなってしまう。

002より003のログ出力が早いのがちょっと意外な感じだけど、イベントのさばき方の問題かな?
DateTime.now()が処理されてるのは002が先という...

computeの場合

重い処理をcompute(マルチスレッド)で実現した場合の挙動を確認してみる。

compute.dart
  Future<void> _test() {
    print("${DateTime.now()}: 001");

    compute(returnTwo, "").then((value) {
      print(value);
    });

    print("${DateTime.now()}: 003");
  }

  static String returnTwo(String param) {
    print("${DateTime.now()}: returnTwo");

    int beforeLoop = DateTime.now().millisecondsSinceEpoch;
    while (true) {
      int nowLoop = DateTime.now().millisecondsSinceEpoch;
      if ((beforeLoop + 2000) <= nowLoop) {
        break;
      }
    }

    return "${DateTime.now()}: 002";
  }
}
I/flutter (21174): 2020-10-14 16:57:54.280819: 001
I/flutter (21174): 2020-10-14 16:57:54.309237: 003
I/flutter (21174): 2020-10-14 16:57:54.480967: returnTwo
I/flutter (21174): 2020-10-14 16:57:56.487022: 002

2秒の待ちポイントがreturnTwoと002の間になってる!
returnTwoより003が早いのはスレッドを立ち上げたりするコストによるもの。

参考

https://sbfl.net/blog/2014/07/10/multithreading-in-dart/
https://cbtdev.net/dart-compute/

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1