千家信息网

Mac OS X NSArray 枚举性能研究的示例分析

发表于:2025-01-23 作者:千家信息网编辑
千家信息网最后更新 2025年01月23日,Mac OS X NSArray 枚举性能研究的示例分析,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。一天,我在思考 NSArray
千家信息网最后更新 2025年01月23日Mac OS X NSArray 枚举性能研究的示例分析

Mac OS X NSArray 枚举性能研究的示例分析,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

一天,我在思考 NSArray 枚举方法 (也称迭代方法): Mac OS X 10.6 和 iOS 4 带来了以块(block)组成的美丽新世界,enumerateObjectsUsingBlock: 方法随之而来。我感觉这个方法要慢于快速枚举 (for (object in array) { ... }),因为有总体开销,但我并不能确定。因此我决定做一次性能测评。

都有哪些枚举方法?

总体来说,我们有4种可以使用的枚举方法 (参考 Mike Ash 的 周五常见问题 2010-04-09: Objective-C 的枚举方法对比)。

1、objectAtIndex: enumeration 使用一个 for 循环,递增循环变量,然后用 [myArray objectAtIndex:index] 来访问元素。这是最基本的枚举形式。

NSUInteger count = [myArray count];  for (NSUInteger index = 0; index < count ; index++) {      [self doSomethingWith:[myArray objectAtIndex:index]];  }

2、NSEnumerator 外部迭代(external iteration)的形式: [myArray objectEnumerator] 返回一个对象,这个对象有 nextObject 方法。我们可以循环调用这个方法,直到返回 nil 为止。

NSEnumerator *enumerator = [myArray objectEnumerator];  id object;  while (object = [enumerator nextObject]) {      [self doSomethingWith:object];  }

3、NSFastEnumerator The idea behind 快速枚举 的思想是利用 C 数组快速访问 来优化迭代。不仅它理论上比传统的 NSEnumerator 更快,而且 Objective-C 2.0 提供了这种简明的语法:

id object;  for (object in myArray) {      [self doSomethingWith:object];  }

4、Block enumeration(块枚举)引入 blocks 后出现的方法,它可以基于块来迭代访问一个数组。它的语法没有快速枚举那么简洁,但它有一个有趣的特性: 并发枚举。如果枚举的顺序并不重要,而且实施的处理可以并发进行,不用锁,这种方法可以在多核系统上带来相当明显的效率提升。详情参考 并发枚举一节。

[myArray enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {      [self doSomethingWith:object];  }];  [myArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {      [self doSomethingWith:object];  }];

线性枚举

首先,我们讨论一下线性枚举:一个项目接着前一个。

图表

结论

有一点令人惊讶的是,NSEnumerator甚至比使用objectAtIndex:还慢。这对于Mac OS X 和IOS是一个事实。我猜想这是由于枚举器在每次迭代时都去检查数组是否被修改。自然地,快速枚举保存了每个原始的名字,因此是最快的解决方案。

对于小的数组,block enumeration 比objectAtIndex:稍慢一点,但在有大量元素的数组里,它的性能变得与fast enumeration差不多快。

fast enumeration和NSEnumeration之间的区别在很多地方已经非常明显:对于iPhone 4S,前者花费约0.037秒而后者需要0.140秒。这已经相差了3.7陪。

奇怪的一点

***在程序中分配 NSArray 和***用objectEnumerator 获取 enumerator 都需要异常长的时间才能完成。例如,在我 2007 年的 17 寸 MacBook Pro 上分配含一个元素的数组,所需时间的中位数是 415 纳秒。但***分配的时候会需要 500,000 纳秒,有时甚至要到 1,000,000 纳秒!获取 enumerator 也是如此:尽管中位数只有 673 纳秒,***获取却要花 500,000 纳秒以上。

我只能猜测其中的原因,但我怀疑延迟加载是罪魁祸首。在实际应用中,你可能不会注意到这一点,因为等到执行你的代码时,Cocoa 或 Cocoa Touch 很可能已经创建过数组了。

并发枚举

如果情况允许,你可以选择用块枚举来并发枚举对象。这意味着计算的工作量可以分散到几个 CPU 内核上。并不是每种枚举过程中的处理都是可并发的,因此只有没用到锁的时候,才能使用并发枚举:要么每一步操作确实是绝对相互独立的,要么有原子性的操作可用 (如 OSAtomicAdd32 之类)。

那么,它相比其他枚举类型有多大优势呢?

图表

结论

元素不多时,并发枚举是目前最慢的方法。主要原因可能是为了让数组能并发访问而做的准备工作和开启线程(我不知道用的是 GCD 还是"传统的"线程,这不重要;这是我们不需关心的实现细节)。

尽管如此,如果数组足够大,并发枚举突然就成了最快的方法了,正如我们所料。在 iPhone 4S 上枚举 100 万个元素,用并发枚举需要 0.024 秒,但快速枚举需要 0.036 秒。相形之下,还是同一个数组,NSEnumeration 要用 0.139 秒! 这已经是非常大的差距了,足有 5.7 倍之多。

在我的办公室,2011 iMac 24"采用了酷睿i7四核CPU,同时在0.0016秒之内列举了百万项。同一数组快速枚举了0.0044秒和NSEnumeration o.oo93秒。那个因数是5.8,它非常接近于ipone 4S的结果。在这里,我期待一个更大的差异,虽然,在我的2007 MacBook采用了Core2 Duo双核CPU,在这里因数刚好是3.7.当同时枚举的阈值成为有用,在某处以我的测试是10,000和50,000分子之间。用更少的分子元素,去掉正常的块迭代。

分配方式

我也想知道枚举的性能会不会受数组创建方式的影响。我测试了两个不同的方法:

  1. 首先创建一个 C 数组,里面引用了数组元素的对象实例,然后再用 initWithObjects:count: 创建NSArray。

  2. 直接创建 NSMutableArray 并依次用 addObject: 添加对象。

结果是迭代过程的没有区别,但分配过程有所不同:initWithObjects:count: 快一些。数组元素很多时,差距更加显著。这个例子创建了一个元素为 NSNumber 的数组:

NSArray *generateArrayMalloc(NSUInteger numEntries) {      id *entries;      NSArray *result;                entries = malloc(sizeof(id) * numEntries);      for (NSUInteger i = 0; i < numEntries; i++) {          entries[i] = [NSNumber numberWithUnsignedInt:i];      }            result = [NSArray arrayWithObjects:entries count:numEntries];            free(entries);      return result;  }

我是如何来测量的?

你可以从 http://darkdust.net/files/arraytest.m 来下载这个测试应用 看看我是如何来测量的。基本上我就是测量重复迭代一个数组(什么处理也不做)1000次需要多长时间。在图表中,取每个数组尺寸的平均值。这个应用的编译选项是关闭优化(-O0)。对于 iOS,我是在一个 iPhone 4S 上进行的测试。对 MAC OS X,我用我家里2007年产的 MacBook Pro 17"和我办公室2011年产的 iMac 24"来测试。MAC OS X的图表显示的是iMac上的结果,在MacBook Pro上的图表看起来与此相似,只是更慢一些。

关于Mac OS X NSArray 枚举性能研究的示例分析问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注行业资讯频道了解更多相关知识。

数组 方法 元素 迭代 图表 对象 纳秒 测试 性能 问题 分配 分析 时间 结果 过程 这是 处理 应用 循环 测量 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 饥荒怎么用专属服务器建新存档 戴尔服务器购买 图书馆电子阅览室网络安全 图书馆安全风险数据库 好的软件开发培训 中国移动软件开发待遇研究院 海南云兆网络技术有限公司电话 sql数据库url怎么获得 手持服务器密码 oracle数据库acl 客户端如何获取服务器发来的证书 珠海市俊泓网络技术 随着科技的发展互联网侵蚀 jsp表格从数据库读取数据 摩宝网络技术 江枫渔火是几年的服务器 文件服务器文件只能查看不能复制 软件开发办什么营业执照 sql语句拷贝数据库 前台显示后台数据库的信息 计算机网络技术英语作文 天津正规软件开发材料 常州华菱软件开发公司 哪个配置可以装服务器系统 缺乏网络安全集中监控 网络安全九龙治水 衡山县网络安全和信息化 我的世界斗罗大陆生存服务器地址 网吧无盘系统用的什么数据库 佛山锨梅网络技术有限公司
0