我遇到了一些相当显著性能问题,同时从转换现有的批量处理Java
到Groovy
。编写的现有批处理过程会Java
定期运行,以读取来自不同数据源的数据并执行一些数据转换。已经发现,在将Java
代码转换为之后,性能会显着下降,出现10倍以上的意外高差距Groovy
。
https://github.com/nicolas-martinez/grava-speed-test上的代码是一个简化的示例,显示了通过简单循环和使用集合闭包进行过滤发现的问题之一。它被设置为Maven
项目,可以很容易地在本地克隆并执行。
以下是Groovy代码的重点:
List items = (0..length).collect()
List even = items.findAll { item -> item > 0 && item.longValue() % 2 == 0 }
和Java代码:
List<Long> items = new ArrayList(length);
for (int i = 0; i < length; i++) {
items.add(Long.valueOf(i + 1));
}
List<Long> even = new ArrayList<Long>();
for(Long item : items){
if (item > 0 && item % 2 == 0) {
even.add(item);
}
}
的测试结果为342ms Groovy
,以下情况为30ms以下Java
:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running tst.speedtest.GroovyFilterTest
testFilter: 500000 elapsed: 342
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.637 sec
Running tst.speedtest.JavaFilterTest
testFilterUsingInterface: 500000 elapsed: 29
testFilter: 500000 elapsed: 27
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.048 sec
如果您对如何提高Groovy性能有任何建议,请告诉我。我们的团队正在考虑使用Groovy,因为它提供了一些高级功能,但是由于迄今为止我们在性能上存在如此高的差距,因此很难证明这一点。
以下是我的硬件配置文件,报告如下system_profiler SPHardwareDataType
:
Hardware Overview:
Model Name: MacBook Pro
Model Identifier: MacBookPro11,3
Processor Name: Intel Core i7
Processor Speed: 2.5 GHz
Number of Processors: 1
Total Number of Cores: 4
L2 Cache (per Core): 256 KB
L3 Cache: 6 MB
Memory: 16 GB
Boot ROM Version: MBP112.0138.B11
SMC Version (system): 2.19f12
这是Java
版本:
java version "1.7.0_72"
Java(TM) SE Runtime Environment (build 1.7.0_72-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.72-b04, mixed mode)
该Groovy
版本2.3.7
如pom.xml中所定义。
更新。
对Groovy
代码进行了建议的修改:
List items = (0..length)
List even = items.findAll { int item -> item > 0 && item % 2 == 0 }
加入试验方法调用的重复来warm up
测试
我跑了单独./speed-test.sh
运行groovy
和java
测试。的启动jvm
从未包含在测试中。
以下是最好的结果,我能够看到在同一jvm进程中以相同的方式运行10次相同的方法,可以进行预热:
/speed-test.sh
Java test
Java testUsingInterface: 500000 elapsed: 44
Java testUsingInterface: 500000 elapsed: 43
Java testUsingInterface: 500000 elapsed: 28
Java testUsingInterface: 500000 elapsed: 11
Java testUsingInterface: 500000 elapsed: 31
Java testUsingInterface: 500000 elapsed: 10
Java testUsingInterface: 500000 elapsed: 9
Java testUsingInterface: 500000 elapsed: 11
Java testUsingInterface: 500000 elapsed: 19
Java testUsingInterface: 500000 elapsed: 19
JavaTest: for testSize=1000000 and repeat=10 total elapsed: 226
Groovy Test
GroovyTest: 500000 elapsed: 199
GroovyTest: 500000 elapsed: 76
GroovyTest: 500000 elapsed: 91
GroovyTest: 500000 elapsed: 80
GroovyTest: 500000 elapsed: 58
GroovyTest: 500000 elapsed: 83
GroovyTest: 500000 elapsed: 91
GroovyTest: 500000 elapsed: 58
GroovyTest: 500000 elapsed: 58
GroovyTest: 500000 elapsed: 67
GroovyTest: for testSize=1000000 and repeat=10 total elapsed: 1073
如@blackdrag所示,Groovy
需要更长的时间进行预热。在预热周期之后,执行仍然需要约5倍的时间(即使不包括初始预热周期)。feature/option-1
如果有人要查看更新的代码,则该代码位于分支上。
我大致上有一些用于性能测试的准则:
由于性能测试是一个非常广泛的领域,尤其是带有微基准测试(因为您可能无法测试自己认为的测试)。对于您的情况,我也给出了一些提示,但是进入所有详细信息可能对该平台而言实在太多了。
首先,您应该考虑要测试的内容。是最高性能,平均性能还是初始性能?有无启动成本?您可能知道JVM使用了部分解释和部分运行时编译的代码。将解释后的代码何时以及如何转换为编译后的代码,例如取决于迭代次数,包含该代码的方法已被调用(以及使用的类型,代码大小和许多其他内容)
如果您追求最高性能,那么junit不是正确的工具。例如,JMH在这里会更好,因为它不仅可以处理预热时间,而且可以在稳定阶段停止。
例如,在第一次使用groovy运行时时会完成很多类加载,其中会加载默认的groovy方法。仅此一项就可以轻松花费您观察到的时间的一半,并且到那时实际上还没有执行任何代码。
@CompileStatic
可以提供帮助,但我们仍不能始终阻止加载Groovy元类系统。因此,即使如此,也可能会产生预热费用。更不用说JVM本身具有预热成本。
我的计算机上的原始代码需要大约752ms的原始代码。仅添加一次迭代的预热就可以减少到14到20毫秒。
而且还有一些逻辑上的断开连接...List items = (0..length).collect()
范围已经是一个列表,因此无需在此处调用collect。通过复制每个元素,这只会产生一个新列表。并且collect()不会将元素转换为long。由于我们正在处理Integer对象,因此实际上不需要通过调用以下命令将其转换为long类型longValue()
。仅纠正这两个问题就已经将执行时间减少了一半(至少在我的计算机上,并且没有预热阶段)。但是预热阶段确实在这里有所作为。因此,通过预热和这些校正,我已经达到了10ms(5万个元素)。为了进行比较,Java版本需要5ms。我发现已经简短地对其进行了测试。因此,如果我用100万个元素重做测试,我会看到73ms(Java)与200ms(Groovy)。当然,我也将Java版本更改为也使用Integer。
添加类型提示以启用基本优化List even = items.findAll {int item -> item > 0 && item % 2 == 0 }
将性能提高到约120ms。
在其他情况下@CompileStatic
或使用invokedynamic运行(invokedynamic版本的性能在很大程度上取决于JVM版本!)也可能有助于提高性能。我假设他们在这项测试中不会做太多事情。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句