以下順序合併排序返回的結果非常快: -斯卡拉:合併排序利用期貨超時
def mergeSort(xs: List[Int]): List[Int] = {
def merge(xs: List[Int], ys: List[Int]): List[Int] = (xs, ys) match {
case (Nil, _) => ys
case (_, Nil) => xs
case (x :: xs1, y :: ys1) => if (x <= y) x :: merge(xs1, ys) else y :: merge(xs, ys1)
}
val mid = xs.length/2
if (mid <= 0) xs
else {
val (xs1, ys1) = xs.splitAt(mid)
merge(mergeSort(xs1), mergeSort(ys1))
}
}
val newList = (1 to 10000).toList.reverse
mergeSort(newList)
然而,當我嘗試使用期貨並行化它,它超時: -
def mergeSort(xs: List[Int]): List[Int] = {
def merge(xs: List[Int], ys: List[Int]): List[Int] = (xs, ys) match {
case (Nil, _) => ys
case (_, Nil) => xs
case (x :: xs1, y :: ys1) => if (x <= y) x :: merge(xs1, ys) else y :: merge(xs, ys1)
}
val mid = xs.length/2
if (mid <= 0) xs
else {
val (xs1, ys1) = xs.splitAt(mid)
val sortedList1 = Future{mergeSort(xs1)}
val sortedList2 = Future{mergeSort(ys1)}
merge(Await.result(sortedList1,5 seconds), Await.result(sortedList2,5 seconds))
}
}
val newList = (1 to 10000).toList.reverse
mergeSort(newList)
我得到一個超時異常。我知道這可能是因爲這段代碼會產生log2 10000線程,這會增加很多延遲,因爲執行上下文Threadpool可能沒有那麼多線程。
1.)我如何利用合併排序中的固有並行性和並行化代碼?
2.)對於什麼用例是期貨有用,什麼時候應該避免?
編輯1:基於到目前爲止,我已經得到了反饋重構代碼: -
def mergeSort(xs: List[Int]): Future[List[Int]] = {
@tailrec
def merge(xs: List[Int], ys: List[Int], acc: List[Int]): List[Int] = (xs, ys) match {
case (Nil, _) => acc.reverse ::: ys
case (_, Nil) => acc.reverse ::: xs
case (x :: xs1, y :: ys1) => if (x <= y) merge(xs1, ys, x :: acc) else merge(xs, ys1, y :: acc)
}
val mid = xs.length/2
if (mid <= 0) Future {
xs
}
else {
val (xs1, ys1) = xs.splitAt(mid)
val sortedList1 = mergeSort(xs1)
val sortedList2 = mergeSort(ys1)
for (s1 <- sortedList1; s2 <- sortedList2) yield merge(s1, s2, List())
}
}
'等待'應該幾乎永遠不會使用,直到你的程序的邊界。另外,你的'merge'函數不是尾遞歸,並且會在略大於10000的列表上造成'StackOverflowError'。 –
@ZiyangLiu做了合併尾遞歸。感謝您指出。 –