Dartの非同期周り(async, await, then)でシングルスレッドでの非同期の挙動を調査したので、マルチスレッドでの非同期の挙動を確認。
DartではIsolateという仕組みでマルチスレッドを実現出来る。
FlutterではIsolateをラップしたcomputeライブラリで簡単に利用出来るのでそちらでの挙動を確認。
動作検証
async thenの場合
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ループで再現してみる。
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(マルチスレッド)で実現した場合の挙動を確認してみる。
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/