为什么 Groovy 的 Map 缩放比 Array 更好?
Why Groovy's Map scales better than Array?
我今天遇到了这个问题,我无法弄清楚为什么 groovy 数组在变大时缩放比例不如 Map 好。
在我的示例中,我创建了一个映射 (LinkedHashMap) 和一个字符串数组 (String[])。然后我从 0 迭代到 10^7,将 i 插入到 Map 或 Array 中。我做了 10 次以确保异常值不会弄乱结果。
int max = 10**7
int numTests = 10
long totalTimeMap = 0
long totalTimeArray = 0
numTests.times{
long start = System.currentTimeMillis()
Map m = [:]
max.times {
m[it] = "${it}"
}
long end = System.currentTimeMillis()
totalTimeMap += (end-start)
}
numTests.times {
long start = System.currentTimeMillis()
String[] s = new String[max]
max.times{
s[it] = "${it}"
}
long end = System.currentTimeMillis()
totalTimeArray += (end-start)
}
println "Map: ${totalTimeMap}"
println "Array: ${totalTimeArray}"
输出出乎意料,因为 Map 的性能比 Array 好:
Map: 49361
Array: 101123
我在java做了同样的实验:
public static void main(String[] args) {
int max = 10000000;
int numTests = 10;
long totalTimeMap = 0;
long totalTimeArray = 0;
for(int i=0; i<numTests; i++){
long start = System.currentTimeMillis();
Map m = new LinkedHashMap();
for(int j=0; j<max; j++){
m.put(j, "" + j);
}
long end = System.currentTimeMillis();
totalTimeMap += (end-start);
}
for(int i=0; i<numTests; i++){
long start = System.currentTimeMillis();
String[] s = new String[max];
for(int j=0; j<max; j++){
s[j] = "" + j;
}
long end = System.currentTimeMillis();
totalTimeArray += (end-start);
}
System.out.println("Map: " + totalTimeMap);
System.out.println("Array: " + totalTimeArray);
}
并且输出符合预期(Array 比 Map 快):
Map: 34564
Array: 12822
我的问题是:为什么使用 Groovy 时 Map 比 Array 快?
当您将字符串添加到 Groovy 中的数组时,您正在创建一个模板化字符串,然后将其转换回 java 字符串(在模板化完成后)因为它必须适合 String[]
对于 Map
版本,您只是存储模板化字符串,因此无需进行评估...
以下基准测试代码:
@Grab('org.gperfutils:gbench:0.4.3-groovy-2.4')
int max = 10000
new groovyx.gbench.BenchmarkBuilder().run {
'Array' {
String[] s = new String[max]
max.times { int idx ->
s[idx] = Integer.toString(idx)
}
}
'List' {
def s = []
max.times{
s << "${it}"
}
}
'Map' {
Map m = [:]
max.times {
m[it] = "${it}"
}
}
}.prettyPrint()
在 Array 方法中我们不使用 GroovyStrings 的地方,给出了结果:
* Groovy: 2.4.3
* JVM: Java HotSpot(TM) 64-Bit Server VM (25.45-b02, Oracle Corporation)
* JRE: 1.8.0_45
* Total Memory: 800.5 MB
* Maximum Memory: 1820.5 MB
* OS: Mac OS X (10.10.3, x86_64)
Options
=======
* Warm Up: Auto (- 60 sec)
* CPU Time Measurement: On
user system cpu real
Array 1819502 6491 1825993 1833209
List 1697948 6533 1704481 1724448
Map 2040521 8932 2049453 2116760
我今天遇到了这个问题,我无法弄清楚为什么 groovy 数组在变大时缩放比例不如 Map 好。
在我的示例中,我创建了一个映射 (LinkedHashMap) 和一个字符串数组 (String[])。然后我从 0 迭代到 10^7,将 i 插入到 Map 或 Array 中。我做了 10 次以确保异常值不会弄乱结果。
int max = 10**7
int numTests = 10
long totalTimeMap = 0
long totalTimeArray = 0
numTests.times{
long start = System.currentTimeMillis()
Map m = [:]
max.times {
m[it] = "${it}"
}
long end = System.currentTimeMillis()
totalTimeMap += (end-start)
}
numTests.times {
long start = System.currentTimeMillis()
String[] s = new String[max]
max.times{
s[it] = "${it}"
}
long end = System.currentTimeMillis()
totalTimeArray += (end-start)
}
println "Map: ${totalTimeMap}"
println "Array: ${totalTimeArray}"
输出出乎意料,因为 Map 的性能比 Array 好:
Map: 49361
Array: 101123
我在java做了同样的实验:
public static void main(String[] args) {
int max = 10000000;
int numTests = 10;
long totalTimeMap = 0;
long totalTimeArray = 0;
for(int i=0; i<numTests; i++){
long start = System.currentTimeMillis();
Map m = new LinkedHashMap();
for(int j=0; j<max; j++){
m.put(j, "" + j);
}
long end = System.currentTimeMillis();
totalTimeMap += (end-start);
}
for(int i=0; i<numTests; i++){
long start = System.currentTimeMillis();
String[] s = new String[max];
for(int j=0; j<max; j++){
s[j] = "" + j;
}
long end = System.currentTimeMillis();
totalTimeArray += (end-start);
}
System.out.println("Map: " + totalTimeMap);
System.out.println("Array: " + totalTimeArray);
}
并且输出符合预期(Array 比 Map 快):
Map: 34564
Array: 12822
我的问题是:为什么使用 Groovy 时 Map 比 Array 快?
当您将字符串添加到 Groovy 中的数组时,您正在创建一个模板化字符串,然后将其转换回 java 字符串(在模板化完成后)因为它必须适合 String[]
对于 Map
版本,您只是存储模板化字符串,因此无需进行评估...
以下基准测试代码:
@Grab('org.gperfutils:gbench:0.4.3-groovy-2.4')
int max = 10000
new groovyx.gbench.BenchmarkBuilder().run {
'Array' {
String[] s = new String[max]
max.times { int idx ->
s[idx] = Integer.toString(idx)
}
}
'List' {
def s = []
max.times{
s << "${it}"
}
}
'Map' {
Map m = [:]
max.times {
m[it] = "${it}"
}
}
}.prettyPrint()
在 Array 方法中我们不使用 GroovyStrings 的地方,给出了结果:
* Groovy: 2.4.3
* JVM: Java HotSpot(TM) 64-Bit Server VM (25.45-b02, Oracle Corporation)
* JRE: 1.8.0_45
* Total Memory: 800.5 MB
* Maximum Memory: 1820.5 MB
* OS: Mac OS X (10.10.3, x86_64)
Options
=======
* Warm Up: Auto (- 60 sec)
* CPU Time Measurement: On
user system cpu real
Array 1819502 6491 1825993 1833209
List 1697948 6533 1704481 1724448
Map 2040521 8932 2049453 2116760