Scala Futures的核心速度很慢

时间:2013-01-09 18:44:34

标签: performance scala future

对于一个研究项目,我编写了一个Scala应用程序,它使用一堆期货来进行并行计算。我注意到在我的本地机器(4核)上,代码运行速度比我们计算机科学研究所的多核服务器(64核)要快。现在我想知道为什么会这样。

详细任务

任务是创建随机布尔k-CNF公式,其中n个不同的变量随机分布在m个子句中,然后看看对于不同的随机分布,公式可解的概率如何降低到50%以下。为此,我实现了概率k-SAT算法,子句生成器和其他一些代码。核心是一个函数,它将n和m作为生成器函数,运行100个期货并等待结果。该函数如下所示:

有问题的代码

def avgNonvalidClauses(n: Int, m: Int)(implicit clauseGenerator: ClauseGenerator) = {

    val startTime = System.nanoTime

    /** how man iteration to build the average **/
    val TRIES = 100

    // do TRIES iterations in parallel 
    val tasks = for (i <- 0 until TRIES) yield future[Option[Config]] {
        val clause = clauseGenerator(m, n)
        val solution = CNFSolver.probKSat(clause)
        solution
    }

    /* wait for all threads to finish and collect the results. we will only wait
     * at most TRIES * 100ms (note: flatten filters out all
     * None's) */
    val results = awaitAll(100 * TRIES, tasks: _*).asInstanceOf[List[Option[Option[Config]]]].flatten

    val millis = Duration(System.nanoTime - startTime, NANOSECONDS).toMillis
    val avg = (results count (_.isDefined)) /  results.length.toFloat

    println(s"n=$n, m=$m => $avg ($millis ms)")

    avg
  }

问题

在我的本地机器上,我得到了这些结果

[info] Running Main 
n=20, m=120 => 0.0 (8885 ms)
n=21, m=121 => 0.0 (9115 ms)
n=22, m=122 => 0.0 (8724 ms)
n=23, m=123 => 0.0 (8433 ms)
n=24, m=124 => 0.0 (8544 ms)
n=25, m=125 => 0.0 (8858 ms)
[success] Total time: 53 s, completed Jan 9, 2013 8:21:30 PM

在64核服务器上,我得到:

[info] Running Main 
n=20, m=120 => 0.0 (43200 ms)
n=21, m=121 => 0.0 (38826 ms)
n=22, m=122 => 0.0 (38728 ms)
n=23, m=123 => 0.0 (32737 ms)
n=24, m=124 => 0.0 (41196 ms)
n=25, m=125 => 0.0 (42323 ms)
[success] Total time: 245 s, completed 09.01.2013 20:28:22

但是,我在两台机器上都满载(服务器平均负载在60到65之间),因此 运行足够的线程。为什么是这样?我做错了什么?

我的本​​地机器有“AMD Phenom(tm)II X4 955处理器”CPU,服务器使用“AMD Opteron(TM)处理器6272”。本地CPU有6800个bogomips,服务器4200.因此,虽然本地CPU的速度提高了1/3,但服务器上的cors却增加了12倍。

其他

如果有一个我的代码的精简示例被推送到github,那么如果你有兴趣的话你可以尝试十二个:https://github.com/Blattlaus/algodemo(这是一个使用Scala 2.10的sbt项目)。

更新

  1. 我通过用42播种随机数生成器来消除任何随机性。这没有任何改变
  2. 我改变了测试版。现在结果更令人惊讶(服务器慢了5倍!)注意:由于输入,所有不可解决子句的平均百分比输出都是zeor。这是正常的和预期的。
  3. 添加了有关CPU的信息
  4. 我注意到在服务器上调用Random.nextInt()的速度要慢10倍。我已经将所有调用包装在一个帮助程序中,如果它们慢于10毫秒,则测量运行时打印机到控制台。在我的本地机器上我得到了一些,通常是10到20毫秒。在服务器上我得到很多mure电话,他们往往超过100毫秒。这可能是问题???

2 个答案:

答案 0 :(得分:2)

你已经找到了答案,问题是使用AtomicLong()的Random.nextInt()。如果经常从不同的线程访问它,那么你将得到缓存抖动,这将在你的64核计算机上更糟糕,因为缓存将进一步分开(电气),因此需要更长的时间来获得必要的缓存线锁。 / p>

有关更多详细信息,请参阅此stackoverflow答案,以及有关如何避免此问题的解决方案(基本上使用线程本地随机数生成器):Contention in concurrent use of java.util.Random

答案 1 :(得分:1)

非规范化浮点数的运算在x86架构上可能要长一个数量级。参见:

Why does changing 0.1f to 0 slow down performance by 10x?

没有检查过您的代码,但考虑到您可能会返回NaN。尝试从测试中删除随机性以验证该假设。