我编写了一个快速排序(方法quicksortF()
),它使用Scala的Future来同时完成分区的递归排序。我还实现了常规快速排序(方法quicksort()
)。不幸的是,当排序列表大于大约1000个元素(900可以工作)时,Future版本会陷入死锁(显然会永远阻塞)。来源如下所示。
我对演员和期货比较陌生。这里有什么问题?
谢谢!
import util.Random
import actors.Futures._
/**
* Quicksort with and without using the Future pattern.
* @author Markus Gumbel
*/
object FutureQuickSortProblem {
def main(args: Array[String]) {
val n = 1000 // works for n = 900 but not for 1000 anymore.
// Create a random list of size n:
val list = (1 to n).map(c => Random.nextInt(n * 10)).toList
println(list)
// Sort it with regular quicksort:
val sortedList = quicksort(list)
println(sortedList)
// ... and with quicksort using Future (which hangs):
val sortedListF = quicksortF(list)
println(sortedListF)
}
// This one works.
def quicksort(list: List[Int]): List[Int] = {
if (list.length <= 1) list
else {
val pivot = list.head
val leftList = list.filter(_ < pivot)
val middleList = list.filter(pivot == _)
val rightList = list.filter(_ > pivot)
val sortedLeftList = quicksort(leftList)
val sortedRightList = quicksort(rightList)
sortedLeftList ::: middleList ::: sortedRightList
}
}
// Almost the same as quicksort() except that Future is used.
// However, this one hangs.
def quicksortF(list: List[Int]): List[Int] = {
if (list.length <= 1) list
else {
val pivot = list.head
val leftList = list.filter(_ < pivot)
val middleList = list.filter(pivot == _)
val rightList = list.filter(_ > pivot)
// Same as quicksort() but here we are using a Future
// to sort the left and right partitions independently:
val sortedLeftListFuture = future {
quicksortF(leftList)
}
val sortedRightListFuture = future {
quicksortF(rightList)
}
sortedLeftListFuture() ::: middleList ::: sortedRightListFuture()
}
}
}
class FutureQuickSortProblem // If not defined, Intellij won't find the main method.?!
答案 0 :(得分:3)
免责声明:我从未以任何严肃的方式亲自使用(2.10之前的)标准库的演员或期货,并且有许多我不喜欢(或至少不理解)的事情。 API,例如与Scalaz或Akka或Play 2.0中的实现进行比较。
但是我可以告诉你,在这种情况下通常的方法是单独组合你的未来,而不是立即声称它们并结合结果。例如,你可以写这样的东西(注意新的返回类型):
import scala.actors.Futures._
def quicksortF(list: List[Int]): Responder[List[Int]] = {
if (list.length <= 1) future(list)
else {
val pivot = list.head
val leftList = list.filter(_ < pivot)
val middleList = list.filter(pivot == _)
val rightList = list.filter(_ > pivot)
for {
left <- quicksortF(leftList)
right <- quicksortF(rightList)
} yield left ::: middleList ::: right
}
}
就像你的vanilla实现一样,这不一定非常有效,而且它也很容易打击堆栈,但它不应该用完线程。
作为旁注,为什么flatMap
上的Future
会返回Responder
而不是Future
?我不知道,neither do some other folks。出于这样的原因,我建议完全跳过现已弃用的2.10之前的标准库基于actor的并发内容。
答案 1 :(得分:1)
根据我的理解,调用对Future的应用(就像连接递归调用的结果时一样)将阻塞,直到检索到结果。