我在 Scala 和 Java 版本的实现之间遇到了一些几乎相同的性能差异。我看到 Java 版本比 Scala 版本快 68%。知道为什么会这样吗?
Java 版本:
public class Util {
public static Set < String > toBigramsJava(String s1) {
Set <String> nx = new HashSet <String> ();
for (int i = 0; i < s1.length() - 1; i++) {
char x1 = s1.charAt(i);
char x2 = s1.charAt(i + 1);
String tmp = "" + x1 + x2;
nx.add(tmp);
}
return nx;
}
Scala 版本:
object Util {
def toBigramsScala(str: String): scala.collection.mutable.Set[String] = {
val hash: scala.collection.mutable.Set[String] = scala.collection.mutable.HashSet[String]()
for (i <-0 to str.length - 2) {
val x1 = str.charAt(i)
val x2 = str.charAt(i + 1)
val tmp = "" + x1 + x2
hash.add(tmp)
}
return hash
}
测试结果:
scala> Util.time(for(i<-1 to 1000000) {Util.toBigramsScala("test test abc de")})
17:00:05.034 [info] Something took: 1985ms
Util.time(for(i<-1 to 1000000) {Util.toBigramsJava("test test abc de")})
17:01:51.597 [info] Something took: 623ms
系统:
我在具有 4 个内核和 8Gig RAM 的 Ubuntu 14.04 上运行它。 Java 版本 1.7.0_45,Scala 版本 2.10.2。
关于我的 blog 有更多信息.
最佳答案
我用这个 scala 版本得到了大致相同的结果
object Util {
def toBigramsScala(str: String) = {
val hash = scala.collection.mutable.Set.empty[String]
var i: Int = 0
while (i < str.length - 1) {
val x1 = str.charAt(i)
val x2 = str.charAt(i + 1)
val tmp = new StringBuilder().append(x1).append(x2).toString()
hash.add(tmp)
i += 1
}
hash
}
}
我记得 scala 中的 for 循环实现为对 Function0 上的 apply() 方法的调用,这是超形态方法调用(从 JVM/JIT 的角度来看是昂贵的)。加上可能由 javac 进行的一些字符串连接优化。
我没有通过查看生成的字节码来检查我的假设,而是用 while 替换 for 和 StringBuilder 的字符串连接使得差异可以忽略不计。
Time for Java Version: 451 millis
Time for Scala Version: 589 millis
关于java - Scala vs Java 性能(HashSet 和二元语法生成),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25596471/