map
私は最近、返される関数がFuture[T]
順次実行されているマシンで奇妙な動作に遭遇しました。これと同じ問題は他のマシンでは発生しません。作業は期待どおりにインターリーブされます。これは、Scala が少し賢すぎてExecutionContext
、マシンのリソース (1 つのコア、1 つのワーカー) に一致するものを選択したためである可能性が高いことを後で発見しました。
問題を再現する簡単なコードを次に示します。
import scala.concurrent._
import scala.concurrent.duration._
val ss = List("the", "quick", "brown", "fox",
"jumped", "over", "the", "lazy", "dog")
def r(s: String) : Future[String] = future {
for (i <- 1 to 10) yield {
println(String.format("r(%s) waiting %s more seconds...",
s, (10 - i).toString))
Thread.sleep(1000)
}
s.reverse
}
val f_revs = ss.map { r(_) }
println("Look ma, no blocking!")
val rev = f_revs.par.map { Await.result(_, Duration.Inf) }.mkString(" ")
println(rev)
奇妙な動作を示すマシンでこれを実行すると、次のような順次出力が生成されます。
Look ma, no blocking!
r(the) waiting 9 more seconds...
r(the) waiting 8 more seconds...
r(the) waiting 7 more seconds...
カスタムの提供ExecutionContext
:
val pool = Executors.newFixedThreadPool(1)
implicit val ec = ExecutionContext.fromExecutor(pool)
スレッドがこのマシンでインターリーブできるようにします。しかし、ここで新たな問題が発生しました。スレッド プールがシャットダウンせず、プログラムが無期限に停止します。どうやら、これはs の予想される動作であり、どこかFixedThreadPool
に置くことでシャットダウンできます。pool.shutdown()
私を頑固と呼んでください。しかし、スレッド プールにシャットダウンを指示する必要はありません。デフォルトのプールと同じように、すべてのキューが空になったときに (おそらく少し遅れて) シャットダウンするようにプールを構成する方法はありますか? ExecutionContext
ドキュメントに目を通しましたが、探しているものが見つかりません。