9

我注意到使用 anNSDateFormatter可能非常昂贵。我发现分配和初始化对象已经消耗了很多时间。
此外,似乎NSDateFormatter在多个线程中使用 an 会增加成本。是否存在线程必须相互等待的阻塞?

我创建了一个小型测试应用程序来说明问题。请检查一下。

产生此类费用的原因是什么?如何提高使用率?


17.12。- 更新我的观察:我不明白为什么线程在并行处理时比串行运行时运行时间更长。只有在使用 NSDateFormatter 时才会出现时间差。

4

6 回答 6

17

注意:您的示例程序在很大程度上是一个微型基准,并且非常有效地最大程度地放大了日期格式化程序的成本。你是在比较什么都不做和做某事。因此,无论那个东西是什么,它看起来都比什么慢。

这样的测试非常有价值,而且极具误导性。微基准通常仅在您拥有 Teh Slow 的真实案例时才有用。如果你要让这个基准测试速度提高 10 倍(事实上,你可能可以按照我在下面的建议),但现实世界的情况只是你的应用程序中使用的总 CPU 时间的 1%,最终结果不会是显着的速度提高 - 几乎不会引起注意。

产生这种成本的原因是什么?

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

最有可能的是,成本与必须解析/验证日期格式字符串以及必须执行任何类型的特定于语言环境的 goop 相关NSDateFormatter。Cocoa 对本地化有非常彻底的支持,但这种支持是以复杂性为代价的。

看看你是如何编写一个相当棒的示例程序的,你可以在 Instruments 中启动你的应用程序并尝试各种 CPU 采样工具,以了解消耗 CPU 周期的内容以及 Instruments 的工作原理(如果你发现任何有趣的东西,更新你的问题! )。

是否存在线程必须相互等待的阻塞?

当您使用来自多个线程的单个格式化程序时,我很惊讶它不会简单地崩溃。 NSDateFormatter没有特别提到它是线程安全的。因此,您必须假设它不是线程安全的。

如何改进使用?

不要创建这么多日期格式化程序!

要么保留一个用于一批操作,然后摆脱它,或者如果您一直使用它们,请在应用程序运行开始时创建一个并保留直到格式更改。

对于线程,如果你真的需要的话,每个线程都保留一个(我敢打赌,这太过分了——你的应用程序的架构使得每批操作创建一个会更明智)。

于 2010-12-14T17:54:12.130 回答
5

我喜欢使用 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;
}
于 2011-03-03T17:14:33.020 回答
3

使用-initWithDateFormat:allowNaturalLanguage:而不是-init跟随-setDateFormat:应该更快(可能〜2x)。

不过,总的来说,bbum 所说的:缓存您的日期格式化程序以获取热代码。

(编辑:这在 iOS 6/OSX 10.8 中不再适用,它们现在应该都一样快)

于 2010-12-14T19:26:30.507 回答
3

使用 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;
}
于 2014-03-18T12:00:13.993 回答
2

由于NSDateFormatterAND 格式和语言环境更改的创建/初始化成本很高。我创建了一个“工厂”类来处理我的NSDateFormatters.

我有一个实例,根据格式和语言环境信息,在我创建的那一刻,NSCache我最多可以存储 15 个实例。NSDateFormatter因此,稍后当我再次需要它们时,我NSDateFormatter使用语言环境“pt-BR”以某种格式“dd/MM/yyyy”询问我的班级,我的班级给了对应的已经加载的NSDateFormatter实例。

您应该同意,在大多数标准应用程序中,每个运行时拥有超过 15 种日期格式是一种边缘情况,所以我认为这是缓存它们的一个很大的限制。如果您只使用 1 或 2 种不同的日期格式,您将只有这个数量的加载NSDateFormatter实例。听起来很适合我的需求。

如果你想试试,我在 GitHub 上公开了

于 2013-04-27T07:08:47.253 回答
0

我认为最好的实现如下:

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;
         }
    }
}
于 2016-04-18T14:04:09.763 回答