基准测试很有趣! :)
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{ @autoreleasepool {
NSMutableSet *masterSet = [NSMutableSet set];
for (NSInteger i = 0; i < 100000; i++) {
[masterSet addObject:[NSNumber numberWithInteger:i]];
}
clock_t start = clock();
for (NSInteger i = 0; i < 100; i++) {
@autoreleasepool {
[NSMutableSet setWithSet:masterSet];
}
}
NSLog(@"a: --- %lu", clock() - start);
sleep(1);
start = clock();
for (NSInteger i = 0; i < 100; i++) {
@autoreleasepool {
[[masterSet mutableCopy] autorelease];
}
}
NSLog(@"b: --- %lu", clock() - start);
return 0;
} }
在我的机器 (10.7) 上,setWithSet: 比 -mutableCopy 慢约 3 倍(有人想在 iOS 5 上尝试吗?:))
现在的问题是:为什么?
-mutableCopy 大部分时间都花在 CFBasicHashCreateCopy() 中(请参阅CFBasicHash.m)。这似乎是直接复制哈希桶,没有重新哈希。
Running Time Self Symbol Name
256.0ms 61.5% 0.0 -[NSObject mutableCopy]
256.0ms 61.5% 0.0 -[__NSCFSet mutableCopyWithZone:]
256.0ms 61.5% 0.0 CFSetCreateMutableCopy
255.0ms 61.2% 156.0 CFBasicHashCreateCopy
97.0ms 23.3% 44.0 __CFSetStandardRetainValue
-setWithSet 枚举集合的每个值,然后将其添加到新集合中。从 CFBasicHashAddValue 的实现(同样在 CFBasicHash.m 中)看来,它正在重新散列集合中的每个值。
Running Time Self Symbol Name
1605.0ms 86.0% 0.0 +[NSSet setWithSet:]
1605.0ms 86.0% 2.0 -[NSSet initWithSet:copyItems:]
1232.0ms 66.0% 68.0 -[__NSPlaceholderSet initWithObjects:count:]
1080.0ms 57.8% 299.0 CFBasicHashAddValue
324.0ms 17.3% 28.0 -[NSSet getObjects:count:]
272.0ms 14.5% 75.0 __CFBasicHashFastEnumeration
这种重新散列在 CFSet 级别是有意义的。 CFSet 在 callBacks 参数中采用 CFSetHashCallBack;因此,两个 CFNumber 的 CFSet 可以指定不同的散列例程。 Foundation 的 NSSet 在底层使用 CFSet,并有一个调用 -[NSObject hash] 的 CFSetHashCallBack 函数。 (虽然我猜苹果可以优化这种情况并避免当两个集合具有相同的哈希回调时重新哈希)。
请注意,此基准测试仅适用于 NSSet(属于 NSNumbers),其他集合类可能具有不同的性能特征。