温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2021-12-31 14:21:21 来源:亿速云 阅读:130 作者:柒染 栏目:编程语言

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];  }];

线性枚举

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

图表

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

结论

有一点令人惊讶的是,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 之类)。

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

图表

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

结论

元素不多时,并发枚举是目前最慢的方法。主要原因可能是为了让数组能并发访问而做的准备工作和开启线程(我不知道用的是 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;  }

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

我是如何来测量的?

你可以从 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 枚举性能研究的示例分析问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI