Multithreading Scala:使用期货超时合并排序
以下顺序合并排序非常快地返回结果:-Multithreading Scala:使用期货超时合并排序,multithreading,scala,concurrency,functional-programming,Multithreading,Scala,Concurrency,Functional Programming,以下顺序合并排序非常快地返回结果:- 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
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)
但是,当我尝试使用Futures将其并行化时,它会超时:-
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个线程,这增加了很多延迟,因为执行上下文线程池可能没有那么多线程
一,。如何利用合并排序中固有的并行性并并行化此代码
二,。什么用例是有用的,什么时候应该避免
编辑1:根据到目前为止我得到的反馈重构代码:-
通常在使用Futures时,您应该尽可能少地等待,并且更喜欢在Futures中工作,并且注意您正在使用的执行上下文 作为一个示例,以下是您如何改变这一点:
def mergeSort(xs: List[Int]): Future[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) 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)
}
}
val newList = (1 to 10000).toList.reverse
Await.result(mergeSort(newList), 5 seconds)
然而,这里仍然有大量的开销。通常情况下,您只会并行化大量大小的工作块,以避免被开销控制,在这种情况下,这可能意味着当递归达到低于某个恒定大小的列表时,会退回到单线程版本。Await几乎永远不会被使用,直到程序的边界。此外,您的合并函数不是尾部递归的,并且会在大小略大于10000的列表上导致StackOverflower错误。@ZiyangLiu已使合并尾部递归。谢谢你指出。谢谢你的回复。您能否详细说明一下:-“注意您正在使用的执行上下文”?基本上只是不同的执行上下文会导致不同的性能影响,所以您应该记住这一点。这是一件很容易忘记的事情,因为它大部分都是由无形的隐含义来处理的。通常这并不重要,但有时确实如此。这有一个很好的概述:
def mergeSort(xs: List[Int]): Future[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) 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)
}
}
val newList = (1 to 10000).toList.reverse
Await.result(mergeSort(newList), 5 seconds)