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)