Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Sleep

💡 お知らせ: このドキュメントはAIによって翻訳されています。表現に違和感がある場合は、原文(英語)を参照するか、翻訳にご協力ください。

Flix は、現在のスレッドを一時停止するためのライブラリエフェクトとして Sleep を提供しています。Sleep エフェクトにはデフォルトハンドラがあるため、main の中で明示的に runWithIO を呼び出す必要はありません。中心となるモジュールは Time.Sleep です。

Sleep エフェクト

Sleep エフェクトは、次の 1 つの操作を持ちます。

pub eff Sleep {
    /// 現在のスレッドを、指定された期間 `d` だけスリープさせます。
    def sleep(d: Duration): Unit
}

Duration(期間)は、Time.Duration モジュールの secondsmillisecondsminutes などのヘルパー関数を使って作成します。

基本的なスリープ

Sleep のもっとも単純な使い方は、一定の期間だけ一時停止することです。

use Time.Duration.seconds
use Time.Sleep

def main(): Unit \ { Sleep, IO } =
    println("Going to sleep...");
    Sleep.sleep(seconds(1));
    println("Woke up!")

何もしないスリープ

withNoOp ハンドラはすべてのスリープをスキップします。これは、遅延を含むコードを実際に待つことなくテストしたい場合に便利です。

use Time.Duration.seconds
use Time.Sleep

def main(): Unit \ IO =
    run {
        println("Going to sleep...");
        Sleep.sleep(seconds(10));
        println("Woke up instantly!")
    } with Sleep.withNoOp

withNoOpSleep エフェクトを完全に処理するため、結果の型にはもはや Sleep は含まれません。

Middleware

Time.Sleep モジュールは、いくつかの Middleware(ミドルウェア)ハンドラを提供しています。これらは、スリープの期間をインターセプトして変換したうえで、背後にある Sleep エフェクトへ転送します。Middleware は Sleep を再送出(re-raise)するため、複数の層を合成できます。

Middleware説明
withConstantすべてのスリープ期間を固定値に置き換えます。
withScale各期間に係数を掛けます。
withMaxSleep個々のスリープを最大値までに制限します。
withMinSleep各スリープが最小値以上になるようにします。
withMaxTotalSleepすべての呼び出しにわたる累積スリープを上限内に抑えます。
withJitter各期間にランダムなジッター(±係数)を加えます。
withLoggingLogger エフェクトを介して各スリープ期間をログに記録します。
withCollectスリープする代わりに、すべての期間をリストに収集します。

たとえば、withMaxSleep は各スリープを最大値までに制限し、withLogging は各期間をログに記録します。

use Time.Duration.{milliseconds, seconds}
use Time.Sleep

def main(): Unit \ { Logger, Sleep, IO } =
    run {
        println("Sleeping for 2 seconds (capped to 500ms)...");
        Sleep.sleep(seconds(2));
        println("Done!")
    } with Sleep.withMaxSleep(milliseconds(500))
      with Sleep.withLogging

Middleware の合成

各 Middleware は Sleep を再送出するため、自然に積み重ねる(スタックする)ことができます。次の例では、各スリープに ±20% のランダムなジッターを加え、その結果の期間をログに記録します。

use Math.Random
use Time.Duration.{seconds}
use Time.Sleep

/// `withJitter` と `withLogging` を合成して、スリープ期間に ±20% の
/// ランダムなジッターを加え、各スリープを `Logger` エフェクトを介してログに記録します。
def main(): Unit \ { Logger, Random, Sleep, IO } =
    run {
        println("Sleeping 3 times with ±20% jitter...");
        Sleep.sleep(seconds(1));
        Sleep.sleep(seconds(2));
        Sleep.sleep(seconds(3));
        println("Done!")
    } with Sleep.withJitter(0.2)
      with Sleep.withLogging

順序が重要です。withJitter は元の期間をインターセプトしてジッターを適用し、Sleep を再送出します。その後、withLogging ハンドラはジッターが適用された期間を見ることになります。