Как минимизировать затраты на выделение и инициализацию NSDateFormatter? - PullRequest
9 голосов
/ 14 декабря 2010

Я заметил, что использование NSDateFormatter может быть довольно дорогостоящим. Я понял, что выделение и инициализация объекта уже отнимает много времени.
Кроме того, кажется, что использование NSDateFormatter в нескольких потоках увеличивает затраты. Может ли быть блокировка, когда потоки должны ждать друг друга?

Я создал небольшое тестовое приложение для иллюстрации проблемы. Пожалуйста, проверьте это.

В чем причина таких затрат и как я могу улучшить использование?


17,12. - Чтобы обновить мои наблюдения: я не понимаю, почему потоки работают дольше при параллельной обработке по сравнению с последовательным порядком. Разница во времени возникает только при использовании NSDateFormatter.

Ответы [ 6 ]

17 голосов
/ 14 декабря 2010

Примечание : Ваша примерная программа является очень микро-эталоном и очень эффективно максимально увеличивает стоимость форматера даты. Вы сравниваете абсолютно ничего не делая с что-то делаете . Таким образом, независимо от того, что это что-то , оно будет казаться чем-то раз медленнее ничто .

Такие тесты чрезвычайно ценны и вводят в заблуждение. Микро-тесты обычно полезны только тогда, когда у вас есть реальный пример Teh Slow. Если бы вам пришлось сделать этот тест в 10 раз быстрее (что, на самом деле, вы могли бы сделать с тем, что я предлагаю ниже), но реальный случай составляет всего 1% от общего процессорного времени, используемого в вашем приложении, конечный результат не будет резкое улучшение скорости - это будет едва заметно.

В чем причина таких расходов?

NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyyMMdd HH:mm:ss.SSS"];

Скорее всего, стоимость связана как с необходимостью анализа / проверки строки формата даты, так и с выполнением любого вида локали, специфичного для языка, который делает NSDateFormatter. Какао имеет чрезвычайно тщательную поддержку локализации, но эта поддержка обходится за счет сложности.

Видя, как вы написали довольно классный пример программы, вы можете запустить свое приложение в Instruments и попробовать различные инструменты выборки CPU, чтобы понять, как потребляются циклы CPU и как работают Instruments (если вы найдете что-нибудь интересное, пожалуйста обновите свой вопрос!).

Может ли быть блокировка, когда потоки должны ждать друг друга?

Я удивлен, что это не просто сбой, когда вы используете один форматер из нескольких потоков. NSDateFormatter специально не упоминает, что это потокобезопасный. Таким образом, вы должны предположить, что это не потокобезопасно.

Как я могу улучшить использование?

Не создавайте так много форматеров даты!

Либо оставьте один для пакета операций, а затем избавьтесь от него или, если вы используете их все время, создайте его в начале работы вашего приложения и держите его до изменения формата.

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

5 голосов
/ 03 марта 2011

Мне нравится использовать последовательную очередь GCD для обеспечения безопасности потоков, это удобно, эффективно и результативно.Что-то вроде:

dispatch_queue_t formatterQueue = dispatch_queue_create("formatter queue", NULL);
NSDateFormatter *dateFormatter;
// ...
- (NSDate *)dateFromString:(NSString *)string
{
    __block NSDate *date = nil;
    dispatch_sync(formatterQueue, ^{
        date = [dateFormatter dateFromString:string];
    });
    return date;
}
3 голосов
/ 18 марта 2014

Используйте GDC dispath_once, и все хорошо.Это обеспечит синхронизацию между несколькими потоками и гарантирует, что форматер даты создается только один раз.

+ (NSDateFormatter *)ISO8601DateFormatter {
    static NSDateFormatter *formatter;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        formatter = [[NSDateFormatter alloc] init];
        formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
    });
    return formatter;
}
3 голосов
/ 14 декабря 2010

Использование -initWithDateFormat:allowNaturalLanguage: вместо -init с последующим -setDateFormat: должно быть намного быстрее (вероятно, ~ 2x).

В общем, как сказал Ббум: кэшируйте ваши средства форматирования даты для горячего кода.

(Изменить: это больше не верно в iOS 6 / OSX 10.8, теперь все они должны быть одинаково быстрыми)

2 голосов
/ 27 апреля 2013

С момента создания / инициализации NSDateFormatter И изменения формата и локали стоят дорого. Я создал «фабричный» класс для повторного использования моего NSDateFormatters.

У меня есть экземпляр NSCache, где я храню до 15 NSDateFormatter экземпляров, основываясь на информации о формате и локали, в момент, когда я их создал. Итак, спустя некоторое время, когда они мне снова понадобятся, я спрашиваю у своего класса какой-то NSDateFormatter формата "dd / MM / yyyy", используя локаль "pt-BR", и мой класс дает корреспонденту уже загруженный экземпляр NSDateFormatter.

Вы должны согласиться с тем, что в большинстве стандартных приложений рекомендуется иметь более 15 форматов даты на одну среду выполнения, поэтому я предполагаю, что это отличный предел для их кэширования. Если вы используете только 1 или 2 разных формата даты, у вас будет только это количество загруженных NSDateFormatter экземпляров. Звучит хорошо для моих нужд.

Если вы хотите попробовать, Я опубликовал это на GitHub .

0 голосов
/ 18 апреля 2016

Я думаю, что лучшая реализация, как показано ниже:

NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary];
NSDateFormatter *dateFormatter = threadDictionary[@”mydateformatter”];
if(!dateFormatter){
    @synchronized(self){
        if(!dateFormatter){
            dateFormatter = [[NSDateFormatter alloc] init];
           [dateFormatter setDateFormat:@”yyyy-MM-dd HH:mm:ss”];
           [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@”Asia/Shanghai”]];
          threadDictionary[@”mydateformatter”] = dateFormatter;
         }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...