2

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

2 回答 2

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在 a 上Future返回 aResponder而不是 a Future?我不知道,其他一些人也不知道。出于这样的原因,我建议完全跳过现已弃用的 2.10 之前标准库基于参与者的并发内容。

于 2012-12-16T18:08:54.120 回答
1

据我了解,在 Future 上调用 apply (就像您在连接递归调用的结果时所做的那样)将阻塞,直到检索到结果。

于 2012-12-16T15:47:31.457 回答