使用Future的Quicksort最终陷入僵局

时间:2012-12-16 15:15:14

标签: scala deadlock actor future

我编写了一个快速排序(方法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.?!

2 个答案:

答案 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的应用(就像连接递归调用的结果时一样)将阻塞,直到检索到结果。