У меня есть словарь, содержащий второй словарь с 1000 записями. Все записи представляют собой NSStrings типа key = key XXX
и value = 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...
Документы Apple для состояния NSEnumerationConcurrent
:
"the code of the Block must be safe against concurrent invocation."
Думаю, проблема в этом, но в чем проблема моего кода или блока в KVC_access4
, который НЕ безопасен для одновременного вызова?
Правка и заключение
Благодаря отличному решению BJ Homer , у меня работает NSEnumerationConcurrent. Я тщательно рассчитал оба метода. Приведенный выше код в KVC_access3
быстрее и проще для словарей малого и среднего размера. Это намного быстрее на большом количестве словарей. Однако, если у вас есть большой словарь mongo (миллионы или десятки миллионов пар ключ / значение), тогда этот код:
[subDict
enumerateKeysAndObjectsWithOptions:
NSEnumerationConcurrent
usingBlock:
^(id key, id object, BOOL *stop) {
NSUInteger workingLength = [object length];
workingLength += [key length];
OSAtomicAdd64Barrier(workingLength, &ll);
}];
будет до 4 раз быстрее. Точка пересечения для размера - это примерно 1 словарь из 100 000 моих тестовых элементов. Больше словарей и точка кроссовера выше, вероятно, из-за времени настройки.