LoginSignup
1
1

More than 1 year has passed since last update.

DartでSleepを使っちゃいけない場合。Future.delayedとの話

Posted at

Flutter歴一週間にみたない赤ん坊です。バブー。はいはい。

timeout処理を実装するためにFutureのtimeoutメソッドを使用したのですが、これがsleepだとうまく動きませんでした。試行錯誤の末、ようやくawait Future.delayedを使わなければいけない事がわかったので、シェアさせていただきます。

以下のコードは、うさぎとかめが競争するプログラムです。うさぎはsleepで寝てもらい、かめはawait Future.delayedで休んでもらいます。

test.dart
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を使おうというお話でした。

1
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
1
1