Flutter歴一週間にみたない赤ん坊です。バブー。はいはい。
timeout処理を実装するためにFutureのtimeoutメソッドを使用したのですが、これがsleepだとうまく動きませんでした。試行錯誤の末、ようやくawait Future.delayedを使わなければいけない事がわかったので、シェアさせていただきます。
以下のコードは、うさぎとかめが競争するプログラムです。うさぎはsleepで寝てもらい、かめはawait Future.delayedで休んでもらいます。
import 'dart:async';
import 'dart:io';
//計測用
class Timer {
static int started = 0; //開始時間
//リセット
static void reset() {
started = getNow();
}
//現在エポックミリ秒を取得
static int getNow() {
return DateTime.now().millisecondsSinceEpoch;
}
//経過ミリ秒を取得
static int getPassedTime() {
return ((getNow() - started) / 1000).round();
}
//結果をプリント
static void printWithTime(String str) {
print(Timer.getPassedTime().toString() + "秒: $str");
}
}
//待ち処理
Future run(String runner, int duration) async {
Duration _dur = Duration(seconds: duration);
if (runner == "かめ") {
Timer.printWithTime("$runner delay開始");
await Future.delayed(_dur); //awaitのdelay使用。正常にタイムアウト処理される
} else {
Timer.printWithTime("$runner sleep開始");
sleep(_dur); //sleep使用。タイムアウト処理されない
}
Timer.printWithTime("$runner完走");
}
//タイムアウト関数
FutureOr onTimeout(String runner) {
Timer.printWithTime("$runnerタイムアウト");
}
//メイン
main() {
const int waitTime = 10; //待ち時間
const int timeoutTime = 3; //タイムアウト時間
const Duration timeoutDur = Duration(seconds: timeoutTime);
["うさぎ", "かめ"].forEach((runner) async {
Timer.reset();
await run(runner, waitTime)
.timeout(timeoutDur, onTimeout: () => onTimeout(runner));
});
}
それぞれのFutureにtimeoutを設定した結果は、次のようになりました。
0秒: うさぎ sleep開始
10秒: うさぎ完走
0秒: かめ delay開始
3秒: かめタイムアウト
10秒: かめ完走
この結果から分かるに、うさぎはタイムアウトを無視して完全にsleepした後、完走(処理を終了)しています。対してかめはawait Future.delayedをしつつ、律儀にタイムアウトを経てから、完走(処理を終了)しているのが分かります。
続いて、かめ二匹に走ってもらうと、次のようになります。
0秒: かめ delay開始
0秒: かめ delay開始
3秒: かめタイムアウト
3秒: かめタイムアウト
10秒: かめ完走
10秒: かめ完走
先ほどはうさぎのsleepに邪魔されて次のかめがスタート出来ませんでしたが、今回はかめがスタートした後すぐに次のかめもスタートしています。このように、sleepのうさぎは他の非同期処理も抑制していたことが分かります。
Futureのtimeoutを使うときは、sleepではなくawait Future.delayedを使おうというお話でした。