我注意到使用NSDateFormatter
可能会非常昂贵。我发现分配和初始化对象已经消耗了很多时间
此外,似乎在多个线程中使用NSDateFormatter
会增加成本。线程必须等待彼此的阻塞吗?
我创建了一个小型测试应用程序来说明问题。请检查一下。
此类费用的原因是什么?如何改善使用?
17.12。 - 更新我的观察结果:我不理解为什么线程处理时线程运行时间比串行运行时更长。只有在使用NSDateFormatter时才会出现时差。
答案 0 :(得分:17)
注意:您的示例程序非常微观基准,并且非常有效地最大限度地放大了日期格式化程序的成本。您正在比较绝对没有与做某事。因此,无论某事是什么,它似乎某些时间比 nothing 慢。
此类测试极具价值且极具误导性。微基准测试通常仅在您拥有Teh Slow的真实案例时才有用。如果您要将此基准测试速度提高10倍(事实上,您可能会按照我的建议进行操作)但实际情况仅为应用程序中使用的总CPU时间的1%,最终结果不会是显着的速度提升 - 几乎不会引人注意。
这种费用的原因是什么?
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyyMMdd HH:mm:ss.SSS"];
最有可能的是,成本与必须解析/验证日期格式字符串以及必须执行NSDateFormatter
所做的任何类型的特定于语言环境的goop相关联。 Cocoa对本地化提供了非常全面的支持,但这种支持是以复杂性为代价的。
看到你如何编写一个相当棒的示例程序,你可以启动你的应用程序在仪器中尝试各种CPU采样仪器,以了解什么是消耗CPU周期和仪器如何工作(如果你发现任何有趣的,请更新您的问题!)。
线程必须互相等待才能阻塞吗?
我很惊讶当你从多个线程使用单个格式化程序时,它不会简单地崩溃。 NSDateFormatter
没有具体提到它是线程安全的。因此,您必须假设它不是线程安全的。
如何改善用法?
不要创建这么多日期格式化程序!
要么保留一批操作然后将其删除,或者如果你一直使用它们,请在应用程序运行开始时创建一个并保持不变,直到格式发生变化。
对于线程,每个线程保持一个,如果你真的必须(我敢打赌这是过度的 - 你的应用程序的架构是这样的,每批操作创建一个将更加明智)。 / p>
答案 1 :(得分: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;
}
答案 2 :(得分:3)
使用-initWithDateFormat:allowNaturalLanguage:
代替-init
后跟-setDateFormat:
应该快得多(可能是2倍)。
一般来说,bbum说:缓存日期格式化程序以获取热门代码。
(编辑:在iOS 6 / OSX 10.8中不再适用,现在它们应该同样快速)
答案 3 :(得分: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;
}
答案 4 :(得分:2)
由于NSDateFormatter
的创建/初始化以及格式和区域设置更改成本很高。我创建了一个“工厂”类来处理NSDateFormatters
的重用。
我有一个NSCache
实例,在我创建的那一刻,我根据格式和区域设置信息存储多达15个NSDateFormatter
个实例。所以,稍后当我再次需要它们时,我会使用locale“pt-BR”以NSDateFormatter
格式“dd / MM / yyyy”向我的班级询问,而我的班级已经加载了已经加载的通讯员NSDateFormatter
实例。
你应该同意在大多数标准应用程序中每个运行时有超过15种日期格式是一个边缘情况,所以我认为这是缓存它们的一个很大的限制。如果您只使用1或2种不同的日期格式,则只有这个加载的NSDateFormatter
个实例数。听起来不错。
如果您想尝试一下,I made it public on GitHub。
答案 5 :(得分: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;
}
}
}