首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在优化Scala代码时,首先看哪里?

在优化Scala代码时,首先看哪里?
EN

Stack Overflow用户
提问于 2013-02-27 20:51:39
回答 2查看 6.4K关注 0票数 21

我目前需要优化算法的Scala实现,这太慢了。它是以函数的方式实现的,仅使用值(val)和不可变的数据结构。我已经记住了重要的函数(所以在我的代码中有一些可变的映射),这使得我的代码快了一倍,我想知道下一步该做什么。

所以,我并不是在寻找软件优化的通用建议(例如,首先优化你的算法,使用分析器,做基准测试……)而是针对特定于Scala或特定于JVM的优化建议。

因此,我的问题是,在尝试优化Scala代码时,首先应该从哪里开始?通常会导致速度减慢的常见语言结构或模式是什么?

我特别就以下几点征询意见:

  • 我读到for(...)构造很慢,因为每次执行循环体时都会生成一个匿名类。这是真的吗?有没有生成匿名类的其他地方?(例如,当使用带有匿名函数的map()时)
  • 的不可变集合在一般情况下比可变集合慢得多(特别是在涉及映射结构时)?
  • 在Scala2.8、2.9和2.10之间是否有任何显著的性能差异?
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-02-28 00:03:48

在过去,我还不得不优化很多Scala代码。下面不是一个完整的列表,只是一些可能对你有帮助的实际观察:

  • 是的,用while替换for循环会更快,即使是在Scala2.10中也是如此。有关这方面的详细信息,请参阅linked talk in the comments。此外,请注意,使用“(see this post for details).
  • The filtering”(你正在迭代的集合后面的条件)将导致条件的装箱/拆箱,这可能会对性能产生很大影响。不可变和可变的问题仅由您必须执行的更新次数来回答,很难(对我而言)在这里给出一般的答案。
  • 到目前为止,我没有观察到2.8,2.9和2.10之间的显著性能差异。但很明显,这取决于手头的问题。例如,如果你的算法大量使用Range.sum,你会观察到很大的不同(因为这是2.10中的O(1) )。
  • 我注意到,使用相应的Java集合而不是Scala版本也可以带来显着的速度提升(大概在5-10%左右)。例如,对于一个非常具体的问题,我在一个微基准测试中得到了以下结果(显示的是运行时)(注意:不要由此得出结论;请运行您自己的结果)。

ColtBitVector最小值: 0.042平均值: 0.245最大值: 40.120 JavaBitSet最小值: 0.043平均值: 0.165最大值: 4.306 JavaHashSet最小值: 0.191平均值: 0.716最大值: 12.624 JavaTreeSet最小值:0.313Avg:1.428max:457.146 ScalaBitSetImmutable最小值: 64.504平均值: 0.380平均值: 1.675最大值: 13.838 ScalaBitSetMutable最小值: 0.423平均值: 3.693最大值: 9.998 ScalaSetImmutable最小值: 0.458平均值: 2.305最大值:9.998 ScalaSetMutable最小值:0.340Avg:1.332max: 10.974

手头的问题是计算整数集合的简单交集(具有非常特定的集合大小和数量)。我想要演示的是:选择正确/错误的集合可以产生重大影响!同样,我认为很难给出选择这些数据类型中哪种数据类型的一般建议,因为这只告诉我们在这个特殊的交集问题中的性能(但我确实在一些情况下选择了Java的HashSet,而不是其他选择)。还要注意,这个交集问题不需要可变的数据类型。尽管如此,即使在不可变的功能中也可能存在性能差异(尽管对于Set来说,可变集合的速度要快得多,但对于BitSet来说,它是不可变的集合)。因此,根据不同的情况,您可能希望选择可变集合而不是不可变集合来获得最大性能(小心使用!)。

  • 我被告知,声明一个变量private[this] var foo = ...会阻止创建getter/ @specialized函数,并且应该更快(免责声明:我从未确认过在处理泛型类型的microbenchmark).

  • When中,为特定类型定义@specialized版本应该导致getter。我尽量避免泛化,但我可以接受以下内容:尝试使用本机数组。在我的许多基准测试中,我只是最终使用了数组,考虑到它们在JVM中的实现,这是有意义的。

  • 我想到的一个小问题是:我观察到通过origCollection.toSomeCollectionName构造集合与使用伴生对象(即SomeCollectionName(origCollection :_*))构造集合的差异。在许多情况下,后者的速度要快得多。
票数 36
EN

Stack Overflow用户

发布于 2013-02-27 21:02:04

你的代码在运行时会实例化大量的对象吗?例如,Scala的case类,或者map/flatMap的链会导致大量的“不必要的”对象被创建,这可能会减慢代码的速度并给垃圾回收器带来更多的工作。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15112604

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档