8

futuresと timeoutsを組み合わせる方法について、いくつかの良いヒントがあります。ただし、 Future シーケンス sequenceOfFuturesでこれを行う方法に興味があります

私の最初のアプローチは次のようになります

import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits._

object FutureSequenceScala extends App {
  println("Creating futureList")

  val timeout = 2 seconds
  val futures = List(1000, 1500, 1200, 800, 2000) map { ms =>
    val f = future {
      Thread sleep ms
      ms toString
    }
    Future firstCompletedOf Seq(f, fallback(timeout))
  }

  println("Creating waitinglist")
  val waitingList = Future sequence futures
  println("Created")

  val results = Await result (waitingList, timeout * futures.size)
  println(results)

  def fallback(timeout: Duration) = future {
    Thread sleep (timeout toMillis)
    "-1"
  }
}

一連の先物でタイムアウトを処理するより良い方法はありますか、それとも有効な解決策ですか?

4

3 に答える 3

8

このコードには、再検討する必要があるかもしれないいくつかの点があります。手始めに、私はExecutionContextタイムアウトをシミュレートすることだけを目的としてタスクを に送信することはあまり好きではありませんThread.sleepsleep呼び出しがブロックされており、一定時間待機するために純粋にブロックしているタスクが実行コンテキストに含まれないようにすることをお勧めします。ここで私の回答から盗み、純粋なタイムアウト処理のために、その回答で概説したようなものを使用することをお勧めします。これHashedWheelTimerは非常に効率的なタイマーの実装であり、単にスリープするタスクよりもタイムアウト処理に適しています。

さて、あなたがその道を行くなら、私が提案する次の変更は、それぞれの将来の個々のタイムアウト関連の失敗を処理することに関するものです. Future個々の失敗が呼び出しから返された集約を完全に失敗させたい場合はsequence、余分なことは何もしません。それが発生したくない場合、代わりにタイムアウトがデフォルト値を返すようにしたい場合は、次のようrecoverに onを使用できます。Future

withTimeout(someFuture).recover{
  case ex:TimeoutException => someDefaultValue
}

それが完了したら、非ブロッキング コールバックを利用して、次のようなことを行うことができます。

waitingList onComplete{
  case Success(results) => //handle success
  case Failure(ex) => //handle fail
}

各 Future にはタイムアウトがあるため、無限に実行されるわけではありません。そこでブロックし、atMostparam toを介してタイムアウト処理の追加レイヤーを提供する IMO は必要ありませんAwait.result。しかし、これは、ノンブロッキング アプローチに問題がないことを前提としていると思います。本当にそこでブロックする必要がある場合はtimeout * futures.size、長時間待つ必要はありません。これらの先物は並行して実行されています。タイムアウトは、先物自体の個々のタイムアウトと同じくらい長くする必要があります(または、CPU /タイミングの遅延を考慮して少し長くする必要があります)。確かに、タイムアウト * フューチャーの総数であってはなりません。

于 2013-07-16T12:29:36.983 に答える