【问题标题】:Scala for comprehension performanceScala 用于理解性能
【发布时间】:2018-04-18 01:41:13
【问题描述】:

为什么

for (
  a <- 1 to 1000;
  b <- 1 to 1000 - a;
  c <- 1 to 1000 - a - b;
  if (a * a + b * b == c * c && a + b + c == 1000)
) println((a, b, c, a * b * c))

266 毫秒

然后慢一点:

for (a <- 1 to 1000)
  for (b <- 1 to 1000 - a)
    for (c <- 1 to 1000 - a - b)
      if (a * a + b * b == c * c)
        if (a + b + c == 1000)
          println((a, b, c, a * b * c))

62 毫秒

如果我理解正确,这应该是一样的吗?


处理答案后的解决方案:

for (
  a <- 1 to 1000;
  b <- 1 to (1000 - a)
) {
  val c = (1000 - a - b)
  if (a * a + b * b == c * c)
    println((a, b, c, a * b * c))
}

9 毫秒

【问题讨论】:

  • 至少编写您使用的 Scala 版本真的很有用。最多您的操作系统和其他相关信息。
  • 我使用的是 Windows 7 和 2.9.2 版,使用带有 jre7 的 eclipse。
  • 寻找解决方案的奇怪方式——你需要a+b+c==1000,那么为什么不直接设置c = 1000 - a - b呢? (显然这不是问题的答案......)

标签: performance algorithm scala


【解决方案1】:

你的理解是错误的。

当条件在循环体中时会发生这种情况:

// this
for(x <- coll) if(condition) doSomething
// will translate to
coll.foreach{ x => if(condition) doSomething }

与条件在生成器本身时相反:

// this
for(x <- coll if(condition)) dosomething
// will translate to
coll.withFilter(x => condition).foreach{ x => dosomething }

您可以查看The Scala Language Specification 6.16了解更多详情。

【讨论】:

    【解决方案2】:

    您可能需要查看this presentation (slides 13-15) 以了解有关如何在内部翻译 for 循环的详细信息。

    你的例子的主要区别是:

    • for 循环体中的条件(2. 示例)
    • 生成器中的条件(1.示例)

    后者,也称为 for 循环过滤,在设计上存在性能缺陷。为了极大地简化正在发生的事情:在withFilter(这是翻译的第一步)中创建了一个Function2[Object, Boolean] 类型的匿名新函数(用于评估条件)。必须将传递给其apply 函数的参数装箱,因为它是基于Object 定义的。这种装箱/拆箱比直接在 for 循环体中评估 if 条件要慢得多,后者允许直接访问变量。

    【讨论】:

    • 那些幻灯片非常有趣,甚至找到了更好的解决方案:)
    • @Downvoter:您介意解释一下我的回答有什么问题吗?
    猜你喜欢
    • 2014-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-15
    • 2011-11-16
    • 2017-07-18
    • 2016-01-02
    • 1970-01-01
    相关资源
    最近更新 更多