Улучшить производительность для настройки Ivar

Я изменил установщики по умолчанию для класса Objective-C, чтобы разрешить какой-то KVO без фактического добавления наблюдателя к свойству. Это прекрасно работает. Но в некоторых случаях мне нужно присвоить этой системе сотни тысяч свойств.

Таким образом, по соображениям производительности у меня есть собственный дескриптор свойства, который позволяет напрямую устанавливать ivar. Пытаясь настроить производительность, я сохраняю некоторую информацию о свойстве.

Еще одно место, которое я очень осторожно изменю, — это использование object_setIvar(), на которое приходится 60% процессорного времени при назначении в соответствии с инструментами. Причина в том, что object_setIvar вызывает _class_getVariable, что занимает в 3 раза больше времени, чем фактическое назначение (objc_storeStrong()).

Короче говоря: поскольку я могу заранее кэшировать всю информацию в свойстве класса как часть моего дескриптора свойства, как я могу быстрее установить ivar (избегая object_setIvar())?

Вот фактическая функция установки объекта моего класса дескриптора свойства (есть также эквивалент для установки числовых значений):

- (id)setObjectValueNoKVOForOwner:(id)instance newObject:(id)newObject
{
    Class cls = object_getClass(instance);
    BOOL retainNewValue, copyNewValue, releaseOldValue;
    switch (self.setterSemantics)
    {
        case MemberDescriptionSetterSemanticsAssign:
            retainNewValue  = NO;
            copyNewValue    = NO;
            releaseOldValue = NO;
            break;

        case MemberDescriptionSetterSemanticsRetain:
            retainNewValue  = YES;
            copyNewValue    = NO;
            releaseOldValue = YES;
            break;

        case MemberDescriptionSetterSemanticsCopy:
            retainNewValue  = NO;
            copyNewValue    = YES;
            releaseOldValue = YES;
            break;
    }

    if (!_ivar)
    {
        _ivar = class_getInstanceVariable(cls, self.attributes.ivarName);
    }

    if (_ivar)
    {
        id oldObject = object_getIvar(instance, _ivar);
        if (newObject != oldObject)
        {
            if (retainNewValue)
            {
                newObject = [newObject retain];
            }
            else if (copyNewValue)
            {
                newObject = [newObject copy];
            }

            object_setIvar(instance, _ivar, newObject); // Improve this: avoid _class_getVariable

            if (releaseOldValue)
            {
                [oldObject release];
            }
        }
    }

    return [newObject autorelease];
}

Обновление:

Я нашел источники, связанные с object_setIvar(): https://github.com/opensource-apple/objc4/blob/master/runtime/objc-class.mm http://www.opensource.apple.com/source/objc4/objc4-532.2/runtime/objc-private.h http://www.opensource.apple.com/source/objc4/objc4-532.2/runtime/objc-runtime-new.mm

Не кажется "этим" злом реализовать собственную версию object_setIvar(), просто добавив к ней известный класс в качестве аргумента. К сожалению, для этого требуется частный заголовочный файл. Поскольку я ориентируюсь на iOS, кажется, на данный момент я должен отказаться от надежд.

Обновление 2:

Я нашел этот комментарий в том месте, где он тратит время в источниках Apple:

"// FIXME: это можно оптимизировать."

Так что я, вероятно, должен сдаться на этом этапе и надеяться, что это будет улучшено в будущем. На самом деле я действительно не понимаю, что есть такое узкое место в чем-то таком простом, как установка значения для свойства. С другой стороны, приятно видеть, что программисты в Apple тоже люди :).


person benjist    schedule 01.11.2013    source источник


Ответы (1)


сотни тысяч свойств вокруг этой системы

Хотя я не являюсь экспертом в этой области, мое понимание внутренней работы шины процессор-память предполагает, что гораздо лучше изменить ближайшие значения (попадание в кэш L1-3) а не значения, которые находятся далеко друг от друга (промах кеша L1-3).

Поэтому не лучше ли использовать простые непрерывные массивы C ваших значений для быстрого хранения?

person ilya n.    schedule 01.11.2013
comment
Я должен был упомянуть, что пишу ORM. Там я создаю сущности и устанавливаю значения, полученные из базы данных, в свойства класса (там классы неизвестны, поэтому я использую дескрипторы свойств, чтобы узнать о свойствах). Подобно объектам и дескрипторам CoreData, хотя и не таким же. - person benjist; 01.11.2013
comment
Я также должен упомянуть, что на самом деле у меня есть еще одна оптимизация, позволяющая избежать создания всех объектов (с использованием курсора). Тем не менее, у меня есть одно требование, когда мне в какой-то момент нужно создать столько сущностей одновременно. - person benjist; 01.11.2013
comment
Итак, вы знаете структуру памяти ваших объектов и тип свойства. Почему бы не позвонить objc_storeStrong(location, value) напрямую? - person ilya n.; 01.11.2013
comment
Это была и моя первая мысль, глядя на то, что делает object_setIvar(). Но, например, я не буду знать, использует ли фактический класс ARC или нет. Что-то, что вы можете узнать, только используя частные методы. - person benjist; 01.11.2013
comment
Но если вы используете только значения, полученные из базы данных, не будут ли ваши значения в основном скалярами и NSString (возможно, +NSArray...)? А я думал, ты управляешь экземпляром класса? - person ilya n.; 01.11.2013
comment
Нет, это не сработает. Класс сущностей находится под контролем пользователя, ORM знает его только по единожды созданному дескриптору для каждого класса сущностей. Потенциально объект может иметь NSArray в качестве свойства (для лениво вызываемых отношений). - person benjist; 01.11.2013