⏱️

Dartでループ内の処理を並列処理する方法

2024/03/29に公開

使い所

ループ内で各プロセスを逐次処理する必要はないが、ループ全体の完了を待ちたい時。

例えば、複数のファイルを読み込んでから後続処理を行いたい場合、それぞれのダウンロード処理で逐次処理を行うと、待ち時間がファイル数に比例して増加してしまいます。
この場合、ダウンロードを並列に処理して大幅に待ち時間を短縮しつつ、全てのダウンロードを待つことで、後続処理への影響も防げます。

対応方法

await Future.wait(futures)を使うことで、並列処理しつつ全体の完了を待つことができます。

実装例

ループ内の処理をList<Future<*>>型変数に格納してFuture.wait()で実行する。
処理時間:4.3秒

code

import 'dart:math' as math;

void main() async {
  List<Future<void>> futures = [];
  for (int i = 0; i < 10; i++) {
    futures.add(Future(() => process(i)));
  }
  await Future.wait(futures);
  print("done");
}

Future<void> process(final int index) async {
  final waitingSecond = math.Random().nextInt(3);
  await Future.delayed(Duration(seconds: waitingSecond));
  print('process $index');
}

result

process 2
process 3
process 4
process 6
process 9
process 7
process 0
process 1
process 5
process 8
done

https://dartpad.dev/?id=913c33810742fa7943eb662705fe320c

補足

単純にawaitする場合

各プロセスが一件ずつ処理されるので、時間がかかります。
処理時間:19.8秒

cord

...
void main() async {
  for (int i = 0; i < 10; i++) {
    await process(i);
  }
  print("done");
}
...

result

process 0
process 1
process 2
process 3
process 4
process 5
process 6
process 7
process 8
process 9
done

そもそもawaitしない場合

処理自体は早く終わりますが、後続処理が先に実行されてしまいます。
処理時間:4.3秒

cord

...
void main() {
  for (int i = 0; i < 10; i++) {
    process(i);
  }
  print("done");
}
...

result

done
process 0
process 3
process 9
process 2
process 4
process 6
process 8
process 1
process 5
process 7

参照情報

https://api.flutter.dev/flutter/dart-async/Future/wait.html
https://qiita.com/pioneerwalk/items/ebc3309abc04229dbd3a

Discussion