NSDictionary (obj-c) 和 HashMap (java) 之间的性能差异
我用这两种数据结构和这两种不同的语言进行了一些性能测试。 结果不是我所期望的。我认为 obj-c 程序会比 java 程序更快。我的测试表明 java TreeMap 比 cocoa NSDictionary 更快。 用于测试的代码是:
obj-c NSDictionary:
#import <Foundation/Foundation.h>
NSString * getRandomString();
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableDictionary * dict = [NSMutableDictionary dictionary];
unsigned long i;
NSString * string1;
NSString * string2;
NSString * string3;
NSString * lastString;
//dictionary with 100'000 elements
srand(time(NULL));
for (i=0;i<100000;i++){
NSString * aString = getRandomString();
[dict setObject:aString forKey:aString];
if (i == 100)
string1 = aString;
if (i == 1000)
string2 = aString;
if (i == 10000)
string3 = aString;
if (i == 100000-1)
lastString = aString;
}
NSDate * now;
now = [NSDate date];
[dict objectForKey:string1];
NSTimeInterval interval = [now timeIntervalSinceNow];
NSLog(@"%f",interval *-1000);
now = [NSDate date];
[dict objectForKey:string2];
interval = [now timeIntervalSinceNow];
NSLog(@"%f",interval *-1000);
now = [NSDate date];
[dict objectForKey:string3];
interval = [now timeIntervalSinceNow];
NSLog(@"%f",interval *-1000);
now = [NSDate date];
[dict objectForKey:lastString];
interval = [now timeIntervalSinceNow];
NSLog(@"%f",interval *-1000);
[pool drain];
return 0;
}
NSString * getRandomString(){
NSString * tmp = [NSString string];
for (int i = 0 ; i < 10;i++){
tmp = [NSString stringWithFormat:@"%@%c",tmp,rand()%128];
}
return tmp;
}
命令行输出是这样的:
2011-07-12 13:11:48.299 TestBench[1178:a0f] 0.008047
2011-07-12 13:11:48.302 TestBench[1178:a0f] 0.005007
2011-07-12 13:11:48.302 TestBench[1178:a0f] 0.003040
2011-07-12 13:11:48.303 TestBench[1178:a0f] 0.003994
Java TreeSet:
import java.util.Date;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
String string1="",string2="",string3="",lastString="";
TreeMap<String,String> map = new TreeMap<String,String>();
for (long i=0;i<100000;i++){
String aString = getRandomString();
map.put(aString, aString);
if (i == 100)
string1 = aString;
if (i == 1000)
string2 = aString;
if (i == 10000)
string3 = aString;
if (i == 100000-1)
lastString = aString;
}
Date start,end;
start = new Date();
map.get(string1);
end = new Date();
System.out.println(end.getTime()-start.getTime());
start = new Date();
map.get(string2);
end = new Date();
System.out.println(end.getTime()-start.getTime());
start = new Date();
map.get(string3);
end = new Date();
System.out.println(end.getTime()-start.getTime());
start = new Date();
map.get(lastString);
end = new Date();
System.out.println(end.getTime()-start.getTime());
}
public static String getRandomString(){
String toRet = "";
for (int i=0;i<10;i++){
toRet+=(char)(Math.random()*128);
}
return toRet;
}
}
命令行输出是这样的:
0
0
0
0
显然对于 obj-c 来说是以毫秒为单位的。 为什么 TreeMap 这么快?或者...为什么 NSDictionary 这么慢? 谁能给我解释一下吗? 抱歉我的英语很糟糕 非常感谢。
**添加问题****< /em>**** 我对代码进行了这样的修改:
obj-c
#import <Foundation/Foundation.h>
NSString * getRandomString();
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableDictionary * dict = [NSMutableDictionary dictionary];
long int i;
NSString * string1;
NSString * string2;
NSString * string3;
NSString * lastString;
//dictionary with 100'000 elements
srand(time(NULL));
double sum = 0;
for (int j = 0 ;j<10;j++){
NSDate * now;
now = [NSDate date];
for (i=0;i<100000;i++){
NSString * aString = getRandomString();
[dict setObject:aString forKey:aString];
if (i == 100)
string1 = aString;
if (i == 1000)
string2 = aString;
if (i == 10000)
string3 = aString;
if (i == 100000-1)
lastString = aString;
}
NSLog(@"Finished adding elements in %f ms",[now timeIntervalSinceNow]*-1000);
now = [NSDate date];
for (int i = 0;i<1000000;i++)
[dict objectForKey:string1];
for (int i = 0;i<1000000;i++)
[dict objectForKey:string2];
for (int i = 0;i<1000000;i++)
[dict objectForKey:string3];
for (int i = 0;i<1000000;i++)
[dict objectForKey:lastString];
NSTimeInterval interval = [now timeIntervalSinceNow];
sum+=interval;
}
NSLog(@"medium lookup time: %f ms",sum/10/4*-1000);
[pool drain];
return 0;
}
NSString * getRandomString(){
NSString * tmp = [NSString string];
for (int i = 0 ; i < 10;i++){
tmp = [NSString stringWithFormat:@"%@%c",tmp,rand()%128];
}
return tmp;
}
输出:
2011-07-12 14:48:36.519 TestBench[974:a0f] Finished adding elements in 1950.287998 ms
2011-07-12 14:48:38.722 TestBench[974:a0f] Finished adding elements in 1899.537027 ms
2011-07-12 14:48:41.340 TestBench[974:a0f] Finished adding elements in 1939.461946 ms
2011-07-12 14:48:43.681 TestBench[974:a0f] Finished adding elements in 1991.870999 ms
2011-07-12 14:48:45.854 TestBench[974:a0f] Finished adding elements in 1857.455015 ms
2011-07-12 14:48:48.636 TestBench[974:a0f] Finished adding elements in 2205.457032 ms
2011-07-12 14:48:50.782 TestBench[974:a0f] Finished adding elements in 1866.232991 ms
2011-07-12 14:48:53.106 TestBench[974:a0f] Finished adding elements in 1847.414017 ms
2011-07-12 14:48:55.537 TestBench[974:a0f] Finished adding elements in 1982.506990 ms
2011-07-12 14:49:00.629 TestBench[974:a0f] Finished adding elements in 4536.152005 ms
2011-07-12 14:49:00.962 TestBench[974:a0f] medium lookup time: 107.704024 ms
hashmap 的Java
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
String string1="",string2="",string3="",lastString="";
Map<String,String> map = new HashMap<String,String>();
long sum=0;
for (int j=0;j<10;j++){
Date start,end;
start = new Date();
for (long i=0;i<100000;i++){
String aString = getRandomString();
map.put(aString, aString);
if (i == 100)
string1 = aString;
if (i == 1000)
string2 = aString;
if (i == 10000)
string3 = aString;
if (i == 100000-1)
lastString = aString;
}
end = new Date();
System.out.println("Finished adding elements in "+(end.getTime()-start.getTime())+" ms");
start = new Date();
for (int i = 0;i<1000000;i++)
map.get(string1);
for (int i = 0;i<1000000;i++)
map.get(string2);
for (int i = 0;i<1000000;i++)
map.get(string3);
for (int i = 0;i<1000000;i++)
map.get(lastString);
end = new Date();
sum+=end.getTime()-start.getTime();
}
System.out.println("medium lookup time: "+sum/10/4+" ms");
}
public static String getRandomString(){
String toRet = "";
for (int i=0;i<10;i++){
toRet+=(char)(Math.random()*128);
}
return toRet;
}
}
结果:
Finished adding elements in 314 ms
Finished adding elements in 275 ms
Finished adding elements in 263 ms
Finished adding elements in 285 ms
Finished adding elements in 309 ms
Finished adding elements in 284 ms
Finished adding elements in 270 ms
Finished adding elements in 395 ms
Finished adding elements in 320 ms
Finished adding elements in 1804 ms
medium lookup time: 8 ms
treemap 的结果
Finished adding elements in 400 ms
Finished adding elements in 430 ms
Finished adding elements in 474 ms
Finished adding elements in 581 ms
Finished adding elements in 562 ms
Finished adding elements in 599 ms
Finished adding elements in 654 ms
Finished adding elements in 625 ms
Finished adding elements in 638 ms
Finished adding elements in 1750 ms
medium lookup time: 194 ms
所以我认为 NSDictionary 不是用哈希函数而是用树制成的。 为什么在 NSDictionary 中添加元素要花这么多时间? cocoa中有没有与java hashset性能相似的map? 谢谢
I made some perfomance tests with these two datastructures and these two different languages.
The results are not what I've expected. I thought that obj-c program would be faster than the java one. My tests says that java TreeMap is faster than cocoa NSDictionary.
the code used to test is that:
obj-c NSDictionary:
#import <Foundation/Foundation.h>
NSString * getRandomString();
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableDictionary * dict = [NSMutableDictionary dictionary];
unsigned long i;
NSString * string1;
NSString * string2;
NSString * string3;
NSString * lastString;
//dictionary with 100'000 elements
srand(time(NULL));
for (i=0;i<100000;i++){
NSString * aString = getRandomString();
[dict setObject:aString forKey:aString];
if (i == 100)
string1 = aString;
if (i == 1000)
string2 = aString;
if (i == 10000)
string3 = aString;
if (i == 100000-1)
lastString = aString;
}
NSDate * now;
now = [NSDate date];
[dict objectForKey:string1];
NSTimeInterval interval = [now timeIntervalSinceNow];
NSLog(@"%f",interval *-1000);
now = [NSDate date];
[dict objectForKey:string2];
interval = [now timeIntervalSinceNow];
NSLog(@"%f",interval *-1000);
now = [NSDate date];
[dict objectForKey:string3];
interval = [now timeIntervalSinceNow];
NSLog(@"%f",interval *-1000);
now = [NSDate date];
[dict objectForKey:lastString];
interval = [now timeIntervalSinceNow];
NSLog(@"%f",interval *-1000);
[pool drain];
return 0;
}
NSString * getRandomString(){
NSString * tmp = [NSString string];
for (int i = 0 ; i < 10;i++){
tmp = [NSString stringWithFormat:@"%@%c",tmp,rand()%128];
}
return tmp;
}
The command-line output is this:
2011-07-12 13:11:48.299 TestBench[1178:a0f] 0.008047
2011-07-12 13:11:48.302 TestBench[1178:a0f] 0.005007
2011-07-12 13:11:48.302 TestBench[1178:a0f] 0.003040
2011-07-12 13:11:48.303 TestBench[1178:a0f] 0.003994
Java TreeSet:
import java.util.Date;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
String string1="",string2="",string3="",lastString="";
TreeMap<String,String> map = new TreeMap<String,String>();
for (long i=0;i<100000;i++){
String aString = getRandomString();
map.put(aString, aString);
if (i == 100)
string1 = aString;
if (i == 1000)
string2 = aString;
if (i == 10000)
string3 = aString;
if (i == 100000-1)
lastString = aString;
}
Date start,end;
start = new Date();
map.get(string1);
end = new Date();
System.out.println(end.getTime()-start.getTime());
start = new Date();
map.get(string2);
end = new Date();
System.out.println(end.getTime()-start.getTime());
start = new Date();
map.get(string3);
end = new Date();
System.out.println(end.getTime()-start.getTime());
start = new Date();
map.get(lastString);
end = new Date();
System.out.println(end.getTime()-start.getTime());
}
public static String getRandomString(){
String toRet = "";
for (int i=0;i<10;i++){
toRet+=(char)(Math.random()*128);
}
return toRet;
}
}
and the command line output is this:
0
0
0
0
obviously in milliseconds as for obj-c.
Why is TreeMap so fast? or... Why is NSDictionary so slow?
Can anyone explain that to me??
Sorry for my very bad english
Thank you very much.
**ADDING QUESTION********
I made modifications to code like this:
obj-c
#import <Foundation/Foundation.h>
NSString * getRandomString();
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableDictionary * dict = [NSMutableDictionary dictionary];
long int i;
NSString * string1;
NSString * string2;
NSString * string3;
NSString * lastString;
//dictionary with 100'000 elements
srand(time(NULL));
double sum = 0;
for (int j = 0 ;j<10;j++){
NSDate * now;
now = [NSDate date];
for (i=0;i<100000;i++){
NSString * aString = getRandomString();
[dict setObject:aString forKey:aString];
if (i == 100)
string1 = aString;
if (i == 1000)
string2 = aString;
if (i == 10000)
string3 = aString;
if (i == 100000-1)
lastString = aString;
}
NSLog(@"Finished adding elements in %f ms",[now timeIntervalSinceNow]*-1000);
now = [NSDate date];
for (int i = 0;i<1000000;i++)
[dict objectForKey:string1];
for (int i = 0;i<1000000;i++)
[dict objectForKey:string2];
for (int i = 0;i<1000000;i++)
[dict objectForKey:string3];
for (int i = 0;i<1000000;i++)
[dict objectForKey:lastString];
NSTimeInterval interval = [now timeIntervalSinceNow];
sum+=interval;
}
NSLog(@"medium lookup time: %f ms",sum/10/4*-1000);
[pool drain];
return 0;
}
NSString * getRandomString(){
NSString * tmp = [NSString string];
for (int i = 0 ; i < 10;i++){
tmp = [NSString stringWithFormat:@"%@%c",tmp,rand()%128];
}
return tmp;
}
the output:
2011-07-12 14:48:36.519 TestBench[974:a0f] Finished adding elements in 1950.287998 ms
2011-07-12 14:48:38.722 TestBench[974:a0f] Finished adding elements in 1899.537027 ms
2011-07-12 14:48:41.340 TestBench[974:a0f] Finished adding elements in 1939.461946 ms
2011-07-12 14:48:43.681 TestBench[974:a0f] Finished adding elements in 1991.870999 ms
2011-07-12 14:48:45.854 TestBench[974:a0f] Finished adding elements in 1857.455015 ms
2011-07-12 14:48:48.636 TestBench[974:a0f] Finished adding elements in 2205.457032 ms
2011-07-12 14:48:50.782 TestBench[974:a0f] Finished adding elements in 1866.232991 ms
2011-07-12 14:48:53.106 TestBench[974:a0f] Finished adding elements in 1847.414017 ms
2011-07-12 14:48:55.537 TestBench[974:a0f] Finished adding elements in 1982.506990 ms
2011-07-12 14:49:00.629 TestBench[974:a0f] Finished adding elements in 4536.152005 ms
2011-07-12 14:49:00.962 TestBench[974:a0f] medium lookup time: 107.704024 ms
Java
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
String string1="",string2="",string3="",lastString="";
Map<String,String> map = new HashMap<String,String>();
long sum=0;
for (int j=0;j<10;j++){
Date start,end;
start = new Date();
for (long i=0;i<100000;i++){
String aString = getRandomString();
map.put(aString, aString);
if (i == 100)
string1 = aString;
if (i == 1000)
string2 = aString;
if (i == 10000)
string3 = aString;
if (i == 100000-1)
lastString = aString;
}
end = new Date();
System.out.println("Finished adding elements in "+(end.getTime()-start.getTime())+" ms");
start = new Date();
for (int i = 0;i<1000000;i++)
map.get(string1);
for (int i = 0;i<1000000;i++)
map.get(string2);
for (int i = 0;i<1000000;i++)
map.get(string3);
for (int i = 0;i<1000000;i++)
map.get(lastString);
end = new Date();
sum+=end.getTime()-start.getTime();
}
System.out.println("medium lookup time: "+sum/10/4+" ms");
}
public static String getRandomString(){
String toRet = "";
for (int i=0;i<10;i++){
toRet+=(char)(Math.random()*128);
}
return toRet;
}
}
result for hashmap:
Finished adding elements in 314 ms
Finished adding elements in 275 ms
Finished adding elements in 263 ms
Finished adding elements in 285 ms
Finished adding elements in 309 ms
Finished adding elements in 284 ms
Finished adding elements in 270 ms
Finished adding elements in 395 ms
Finished adding elements in 320 ms
Finished adding elements in 1804 ms
medium lookup time: 8 ms
result for treemap
Finished adding elements in 400 ms
Finished adding elements in 430 ms
Finished adding elements in 474 ms
Finished adding elements in 581 ms
Finished adding elements in 562 ms
Finished adding elements in 599 ms
Finished adding elements in 654 ms
Finished adding elements in 625 ms
Finished adding elements in 638 ms
Finished adding elements in 1750 ms
medium lookup time: 194 ms
So i think NSDictionary is not made with hash function but with a tree.
And why it takes so much time to add elements in NSDictionary?
Is there a map in cocoa with similar performances to java hashset?
thank you
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您无法真正比较这些值,因为在 Java 中您有
long
,而在 Cocoa 中您有double
。如果您将NSTimeInterval
(这是一个double
)转换为 long,您将得到完全相同的结果。此外,为了获得有用的结果,仅对方法的一次调用进行计时是不够的。做一个循环并至少调用它几千次。
You can't really compare the values, because in Java you have
long
s and in Cocoa you havedouble
s. If you would cast theNSTimeInterval
(which is adouble
) to long, you'd get the exact same result.Also, to get useful results, timing just one call of the method isn't enough. Make a loop and call it a few thousand times at least.
Java 非常擅长优化不执行任何操作的代码。在这方面它通常比 C/C++ 快得多。然而,当涉及到实际工作时,差异通常要小得多。
map.get()
不执行任何操作,但new Date()
执行此操作,这比System.currentTimeMillis()
慢得多,如果您如果想要对短操作进行计时,最好使用 System.nanoTime() 并计算不会立即丢弃的结果。此外,值得运行大约 2 秒的测试以获得最佳结果。
印刷
Java is very good at optimising code which doesn't do anything. In this regard it is often much faster than C/C++. However when it comes to doing real work the difference is usually much smaller.
map.get()
doesn't do anything butnew Date()
does and this is much slower thanSystem.currentTimeMillis()
If you want to time short operations you are better off usingSystem.nanoTime()
and calculating results which are not immediately discarded.Additionally, it is worth running a test for about 2 seconds to get the best result.
prints