【问题标题】:Scala Future multiple cores - slow performanceScala Future 多核 - 性能缓慢
【发布时间】:2018-01-11 06:42:27
【问题描述】:
    import java.util.concurrent.{Executors, TimeUnit}

    import scala.annotation.tailrec
    import scala.concurrent.{Await, ExecutionContext, Future}
    import scala.util.{Failure, Success}

    object Fact extends App {
      def time[R](block: => R): Long = {
        val t0 = System.nanoTime()
        val result = block // call-by-name
        val t1 = System.nanoTime()

        val t: Long = TimeUnit.SECONDS.convert((t1 - t0), TimeUnit.NANOSECONDS)
        //println(
        // "Time taken seconds: " + t)
        t
      }
      def factorial(n: BigInt): BigInt = {
        @tailrec
        def process(n: BigInt, acc: BigInt): BigInt = {
          //println(acc)
          if (n <= 0) acc
          else process(n - 1, n * acc)
        }

        process(n, 1)
      }

      implicit val ec =
        ExecutionContext.fromExecutor(Executors.newFixedThreadPool(2))
      val f1: Future[Stream[Long]] =
        Future.sequence(
          (1 to 50).toStream.map(x => Future { time(factorial(100000)) }))

      f1.onComplete {
        case Success(s) => {
          println("Success : " + s.foldLeft(0L)(_ + _) + " seconds!")

        }
        case Failure(f) => println("Fails " + f)
      }

      import scala.concurrent.duration._

      Await.ready(Future { 10 }, 10000 minutes)

    }

我有上面的 Factorial 代码需要使用多个内核来更快地完成程序,并且应该使用更多的内核。

所以我改变了,

  • Executors.newFixedThreadPool(1) 使用 1 个核心

  • Executors.newFixedThreadPool(2) 使用 2 个内核

当改为1核时,结果会在127秒后出现。 但是当更改为 2 核 时,我会得到 157 秒

我的疑问是,当我增加核心(并行度)时,它应该会提供良好的性能。但事实并非如此。为什么?

如果我错了或遗漏了什么,请纠正我。

提前致谢。

【问题讨论】:

    标签: scala performance future


    【解决方案1】:

    你是如何测量时间的?您打印的结果不是执行所用的时间,而是每个单独调用的时间总和。

    在 REPL 中运行 Fact.time(Fact.main(Array.empty)) 我分别得到 90 和 178 两个线程和一个线程。似乎有道理...

    【讨论】:

    • 是的,是计算逻辑错误。感谢您解决问题。 :) 高度赞赏。
    • 顺便说一句,foo.foldLeft(0){ _ + _ } 可以写成更短的foo.sum :D
    【解决方案2】:

    首先,Dima 是正确的,您打印的是所有任务的总执行时间,而不是直到最后一个任务完成的总时间。不同之处在于,第一个汇总了所有并行完成的工作的时间,而只有后者显示了多线程的实际速度。

    但是还有另一个重要的影响。当我使用 1、2 和 3 个线程运行此代码并测量总时间(直到 f1 准备好之前的时间)和总并行时间(您打印的那个)时,我得到以下数据(我还减少了从50 到 20 以加快我的测试速度):

    1 - 70 - 70
    2 - 47 - 94
    3 - 43 - 126
    

    乍一看,它看起来不错,因为并行时间除以实时时间与线程数大致相同。但是,如果您仔细观察,您可能会注意到从 1 个线程到 2 个线程的速度只有大约 1.5 倍,而第三个线程的速度只有 1.1 倍。这些数字还意味着当您添加线程时,所有任务的总时间实际上会增加。这似乎令人费解。

    这个难题的答案是您的计算实际上不受 CPU 限制。问题是答案 (factorial(100000)) 实际上是一个很大的数字。事实上,它是如此之大,以至于需要大约 185KB 的内存来存储它。这意味着在计算的后期阶段,您的 factorial 方法实际上变得比 CPU 更受内存限制,因为这个大小足以溢出最快的 CPU 缓存。这就是为什么添加更多线程会减慢每次计算的原因:是的,您计算速度更快,但内存并没有变得更快。因此,当您使 CPU 缓存和内存通道饱和时,添加更多线程(内核)并不会提高性能。

    【讨论】:

    • 感谢您解释更多见解。我的用例是通过更多的 CPU 密集型操作来测试性能。但是你的观点肯定会很好学。谢谢。
    • @ChandrasekarS,我的全部意思是,您的任务只是似乎占用大量 CPU 而实际上占用大量内存。
    猜你喜欢
    • 2021-06-17
    • 1970-01-01
    • 2010-10-14
    • 2015-01-27
    • 2021-06-04
    • 2016-11-09
    • 2021-06-21
    • 2012-05-11
    • 2023-04-07
    相关资源
    最近更新 更多