私はscalafuturesを実装しているときにミスを犯しました。少なくとも、間違いを犯したと思いますが、ミスを修正すると、futuresを使用しない場合よりも実行速度が大幅に低下します。誰かが私が何が起こっているのかを理解するのを手伝ってもらえますか?
5,000回実行する必要がある遅いメソッドがあります。それぞれが独立しており、Doubleを返します。次に、5,000個の戻り値の平均と標準偏差を計算する必要があります。
最初にコーディングしたときは、次のようにコーディングしました。
import actors.Futures._
import util.Random
import actors.Future
def one = {
var results = List[Future[Double]]()
var expectedResult: List[Double] = Nil
var i = 0
while (i < 1000) {
val f = future {
Thread.sleep(scala.util.Random.nextInt(5) * 100)
println("Loop count: " + i)
Random.nextDouble
}
results = results ::: List(f)
println("Length of results list: " + results.length)
results.foreach(future => {
expectedResult = future() :: expectedResult
i += 1
})
}
// I would return the list of Doubles here to calculate mean and StDev
println("### Length of final list: " + expectedResult.length)
}
速く走り、期待通りの結果が得られたので、何も考えていませんでした。実行速度を上げるために詳しく調べたところ(使用可能なすべてのCPUリソースを使用していなかった)、ループカウンターが間違った場所にありforeach
、future
作成ループ内にあり、その結果、先物を早期にブロックします。またはそう思った。
何が起こっているのかを理解できるかどうかを確認するために、いくつかのprintlnステートメントを貼り付けて、何が起こっているのかについて非常に混乱しました...結果リストの長さが最終リストの長さと一致せず、どちらも一致しませんでしたループカウンター!
私は自分が起こっていると思った(あるべき)ことに基づいてコードを次のように変更しましたが、物事ははるかに遅くなり、printステートメントの出力は最初の方法よりも意味がありませんでした。今回は、最終的なリストの長さは理にかなっていますが、ループカウンターは1000にジャンプするようです。
2番目の方法では、使用可能なすべてのCPUリソースを使用します。これは、私が期待するものに沿ったものですが、同じ結果であると確信している場合は、より時間がかかります。
def two = {
var results = List[Future[Double]]()
var expectedResult: List[Double] = Nil
var i = 0
while (i < 1000) {
val f = future {
Thread.sleep(scala.util.Random.nextInt(5) * 100)
println("Loop count: " + i)
Random.nextDouble
}
results = f :: results
i += 1
println("Length of results list: " + results.length)
}
results.foreach(future => {
expectedResult = future() :: expectedResult
})
// I would return the list of Doubles here to calculate mean and StDev
println("### Length of final list: " + expectedResult.length)
}
ここで明らかな何かが欠けていますか?
編集
これを見ている人にとって...問題は、先物ループ内の最終リスト(expectedResult)に先物の結果を再度追加していたことでした-som-snyttによって指摘されました。
したがって、ループを繰り返すたびに、完了した先物を繰り返し繰り返して、次のようになります。
//First Loop:
List(1)
//Second Loop:
List(1,2)
//Third Loop:
List(1,2,3,4)
//... and so on
最終的なリストのパターンは次のとおりです。
List(n, n-1, n-2, ..., 4, 3, 2, 1, 3, 2, 1, 2, 1, 1)
リストは5050アイテムの長さで、Double値であるため、リストの先頭だけを見たときにパターンを確認するのは困難でした。
最終的に、ループの数は実際には100だけであり、必要な5000ではありませんでした。
メソッドのバージョン2は、scala2.9に適しています。