Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

A case study on the performance of Mac OS X NSArray enumeration

2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

Mac OS X NSArray enumeration performance research example analysis, in view of this problem, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible method.

One day, I was thinking about NSArray enumeration methods (also known as iterative methods): Mac OS X 10.6 and iOS 4 brought a beautiful new world of block, and enumerateObjectsUsingBlock: methods followed. I feel that this method is slower than fast enumeration (for (object in array) {...}) because of the overall overhead, but I'm not sure. So I decided to do a performance test.

What are the enumeration methods?

Overall, we have four enumeration methods that we can use (see Mike Ash's Friday FAQ 2010-04-09: Objective-C enumeration methods comparison).

1. ObjectAtIndex: enumeration uses a for loop, increments the loop variable, and then accesses the element with [myArray objectAtIndex:index]. This is the most basic form of enumeration.

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]; }]; 线性枚举 首先,我们讨论一下线性枚举:一个项目接着前一个。 图表

Conclusion

What's surprising is that NSEnumerator is even slower than using objectAtIndex:. This is a fact for Mac OS X and IOS. I guess this is because the enumerator checks to see if the array has been modified at each iteration. Naturally, quick enumerations save each original name, so it is the fastest solution. For small arrays, block enumeration is slightly slower than objectAtIndex:, but in arrays with a large number of elements, its performance becomes almost as fast as fast enumeration.

The difference between fast enumeration and NSEnumeration is already obvious in many places: for iPhone 4S, the former takes about 0.037 seconds while the latter takes 0.140 seconds. There is already a difference of 3.7.

The strange thing.

* it takes an unusually long time to assign NSArray in the program and * * to obtain enumerator with objectEnumerator. For example, on my 17-inch MacBook Pro in 2007, the median time required to allocate an array of one element was 415 nanoseconds. But it takes 500000 nanoseconds, sometimes up to 1000000 nanoseconds, to allocate! The same is true of getting enumerator: although the median is only 673 nanoseconds, it takes more than 500000 nanoseconds to get.

I can only guess why, but I suspect that delayed loading is the culprit. In practice, you may not notice this, because by the time your code is executed, Cocoa or Cocoa Touch will probably have created an array.

Concurrent enumeration

If circumstances permit, you can choose to use block enumeration to concurrently enumerate objects. This means that the computing effort can be spread across several CPU cores. Not all processes in enumerations are concurrent, so concurrent enumerations can only be used when locks are not used: either each step is indeed absolutely independent of each other, or atomic operations are available (such as OSAtomicAdd32).

So how much advantage does it have over other enumerated types?

Chart

Conclusion

When there are not many elements, concurrent enumeration is by far the slowest method. The main reason may be the preparation and thread opening for concurrent access to the array (I don't know whether to use GCD or "traditional" threads, which doesn't matter; this is an implementation detail that we don't need to care about).

However, if the array is large enough, concurrent enumerations suddenly become the fastest way, as we expected. Enumerating 1 million elements on iPhone 4S takes 0.024 seconds to enumerate concurrently, but it takes 0.036 seconds to enumerate quickly. By contrast, it takes 0.139 seconds to NSEnumeration the same array! This is already a very big gap, as much as 5.7 times.

In my office, 2011 iMac 24 "uses Core i7 quad-core CPU and lists millions of items in 0.0016 seconds." The same array quickly enumerates 0.0044 seconds and NSEnumeration o.oo93 seconds. That factor is 5.8, which is very close to the result of ipone 4S. Here, I expect a bigger difference, although my 2007 MacBook uses Core2 Duo dual-core CPU, where the factor is exactly 3.7. When the threshold of simultaneous enumeration becomes useful, at some point my test is between 10000 and 50000 molecules. Remove the normal block iteration with fewer molecular elements.

Distribution mode

I also want to know if the performance of enumerations is affected by the way the array is created. I tested two different methods:

First create a C array that references an object instance of the array elements, and then create a NSArray with initWithObjects:count:.

Create the NSMutableArray directly and use addObject: add objects in turn.

The result is that there is no difference in the iterative process, but the allocation process is different: initWithObjects:count: faster. When there are a lot of array elements, the gap is even more significant. This example creates an array with the element NSNumber:

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

How do I measure it?

You can download this test application from http://darkdust.net/files/arraytest.m and see how I measure it. Basically I measure how long it takes to iterate over an array (doing nothing) 1000 times. In the chart, take the average of each array size. The compilation option for this application is to turn off optimization (- O0). For iOS, I tested it on an iPhone 4S. For MAC OS X, I tested it with MacBook Pro 17 "made in my family in 2007 and iMac 24 produced in my office in 2011." MAC OS X's chart shows the results on iMac, and the chart on MacBook Pro looks similar, but slower.

This is the answer to the sample analysis question on Mac OS X NSArray enumeration performance research. I hope the above content can be of some help to you. If you still have a lot of doubts to be solved, you can follow the industry information channel for more related knowledge.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report