key XXX
,值为element XXX
,其中XXX
是0到元素数量-1之间的数字。(几天前,我问过一个关于包含字典的Objective-C字典的问题。如果您想获取创建字典的代码,请参考该问题。)子字典中所有字符串的总长度为28,670个字符。即:
strlen("key 0")+strlen("element 0")+
//and so on up through
strlen("key 999")+strlen("element 999") == 28670.
考虑这个非常简单的哈希值作为一个指示器,用于判断一个方法是否已经枚举了每个键值对一次且仅一次。
我有一个子程序,使用块完美地访问单个字典键和值:
NSUInteger KVC_access3(NSMutableDictionary *dict){
__block NSUInteger ll=0;
NSMutableDictionary *subDict=[dict objectForKey:@"dict_key"];
[subDict
enumerateKeysAndObjectsUsingBlock:
^(id key, id object, BOOL *stop) {
ll+=[object length];
ll+=[key length];
}];
return ll;
}
// will correctly return the expected length...
如果我在多处理器机器上使用并发块进行尝试,得到的数字接近但不完全符合预期的28670:
NSUInteger KVC_access4(NSMutableDictionary *dict){
__block NSUInteger ll=0;
NSMutableDictionary *subDict=[dict objectForKey:@"dict_key"];
[subDict
enumerateKeysAndObjectsWithOptions:
NSEnumerationConcurrent
usingBlock:
^(id key, id object, BOOL *stop) {
ll+=[object length];
ll+=[key length];
}];
return ll;
}
// will return correct value sometimes; a shortfall value most of the time...
NSEnumerationConcurrent
的苹果文档中写道:
"the code of the Block must be safe against concurrent invocation."
我认为这可能是问题所在,但是我的代码或者KVC_access4
中的代码块对于并发调用来说不是安全的,这就是问题所在。
编辑和结论
感谢BJ Homer的优秀解决方案,我成功地使用了NSEnumerationConcurrent。我对两种方法进行了广泛的时间测试。我在KVC_access3
中的代码在小型和中型字典中更快、更易于使用。它在许多字典中都更快。然而,如果你有一个非常大的字典(数百万或数千万个键/值对),那么这段代码:
[subDict
enumerateKeysAndObjectsWithOptions:
NSEnumerationConcurrent
usingBlock:
^(id key, id object, BOOL *stop) {
NSUInteger workingLength = [object length];
workingLength += [key length];
OSAtomicAdd64Barrier(workingLength, &ll);
}];
速度提高了4倍。尺寸的交叉点大约在我测试元素的100,000个字典中的1个字典。更多的字典,这个交叉点会更高,可能是因为设置时间。