У меня есть код для преобразования большого (много гигабайт) XML-файла в другой формат.
Помимо прочего, мне нужно хранить один или два гигабайта с плавающей точкой в хэш-таблице (два с плавающей точкой)для каждой записи), с int в качестве ключа значения.
В настоящее время я использую NSMutableDictionary и пользовательский класс, содержащий два числа с плавающей запятой:
// create the dictionary
NSMutableDictionary *points = [[NSMutableDictionary alloc] init];
// add an entry (the data is read from an XML file using libxml)
int pointId = 213453;
float x = 42.313554;
float y = -21.135213;
MyPoint *point = [[MyPoint alloc] initWithX:x Y:y];
[points setObject:point forKey:[NSNumber numberWithInt:pointId]];
[point release];
// retrieve an entry (this happens later on while parsing the same XML file)
int pointId = 213453;
float x;
float y;
MyPoint *point = [points objectForKey:[NSNumber numberWithInt:pointId]];
x = point.x;
y = point.y;
Этот набор данных потребляет около800 МБ ОЗУ с файлом XML, с которым я сейчас работаю, и на его выполнение уходит довольно много времени.Я хотел бы иметь более высокую производительность, но еще более важно, чтобы мне потребовалось уменьшить потребление памяти, чтобы я мог обрабатывать еще большие XML-файлы.
objc_msg_send прямо в профиле кода, как и- [NSNumber numberWithInt:]
, и я уверен, что смогу уменьшить использование памяти, вообще избегая объектов, но я не очень разбираюсь в программировании на C (этот проект, безусловно, учит меня!).
Как я могузаменить NSMuableDictionary
, NSNumber
MyPoint
на эффективную структуру данных C?Без каких-либо сторонних библиотечных зависимостей?
Я также хотел бы иметь возможность записать эту структуру данных в файлы на диске, чтобы я мог работать с набором данных, который не полностью помещается в память, но явероятно, может жить без этой возможности.
(для тех, кто не знаком с Objective-C, класс NSMutableDictionary может хранить только объекты Obj-C, и ключи также должны быть объектами. NSNumber и MyPointклассы тупого контейнера, позволяющие NSMutableDictionary работать со значениями float и int.)
РЕДАКТИРОВАТЬ:
Я пытался использовать CFMutableDictionaryхранить структуры согласно образцу кода яблока .Когда словарь пуст, он работает отлично.Но когда словарь растет, он становится все медленнее и медленнее.Примерно на 25% при разборе файла (~ 4 миллиона элементов в словаре) он начинает пыхтеть, на два порядка медленнее, чем раньше в файле.
NSMutableDictionary не имеет той же проблемы с производительностью.Инструменты демонстрируют большую активность, применяя хеши и сравнивая ключи словаря (метод intEqual()
ниже).Сравнение int быстрое, поэтому что-то очень неправильно для его выполнения так часто.
Вот мой код для создания словаря:
typedef struct {
float lat;
float lon;
} AGPrimitiveCoord;
void agPrimitveCoordRelease(CFAllocatorRef allocator, const void *ptr) {
CFAllocatorDeallocate(allocator, (AGPrimitiveCoord *)ptr);
}
Boolean agPrimitveCoordEqual(const void *ptr1, const void *ptr2) {
AGPrimitiveCoord *p1 = (AGPrimitiveCoord *)ptr1;
AGPrimitiveCoord *p2 = (AGPrimitiveCoord *)ptr2;
return (fabsf(p1->lat - p2->lat) < 0.0000001 && fabsf(p1->lon - p2->lon) < 0.0000001);
}
Boolean intEqual(const void *ptr1, const void *ptr2) {
return (int)ptr1 == (int)ptr2;
}
CFHashCode intHash(const void *ptr) {
return (CFHashCode)((int)ptr);
}
// init storage dictionary
CFDictionaryKeyCallBacks intKeyCallBacks = {0, NULL, NULL, NULL, intEqual, intHash};
CFDictionaryValueCallBacks agPrimitveCoordValueCallBacks = {0, NULL /*agPrimitveCoordRetain*/, agPrimitveCoordRelease, NULL, agPrimitveCoordEqual};
temporaryNodeStore = CFDictionaryCreateMutable(NULL, 0, &intKeyCallBacks, &agPrimitveCoordValueCallBacks);
// add an item to the dictionary
- (void)parserRecordNode:(int)nodeId lat:(float)lat lon:(float)lon
{
AGPrimitiveCoord *coordPtr = (AGPrimitiveCoord *)CFAllocatorAllocate(NULL, sizeof(AGPrimitiveCoord), 0);
coordPtr->lat = lat;
coordPtr->lon = lon;
CFDictionarySetValue(temporaryNodeStore, (void *)nodeId, coordPtr);
}
EDIT 2:
Проблема с производительностью была вызвана практически бесполезной реализацией хеширования в примере кода Apple.Я поднял производительность, используя это:
// hash algorithm from http://burtleburtle.net/bob/hash/integer.html
uint32_t a = abs((int)ptr);
a = (a+0x7ed55d16) + (a<<12);
a = (a^0xc761c23c) ^ (a>>19);
a = (a+0x165667b1) + (a<<5);
a = (a+0xd3a2646c) ^ (a<<9);
a = (a+0xfd7046c5) + (a<<3);
a = (a^0xb55a4f09) ^ (a>>16);