Objective-C 高性能的循环
2016-05-04 14:12
375 查看
http://www.oschina.net/translate/high-performance-collection-looping-objective-c
其它翻译版本(1)
Cocoa编程的一个通常的任务是要去循环遍历一个对象的集合 (例如,一个 NSArray, NSSet 或者是 NSDictionary). 这个看似简单的问题有广泛数量的解决方案,它们中的许多不乏有对性能方面问题的细微考虑.首先,是一个免责声明: 相比其它问题而言,一个 Objective-C 方法原始的速度是你在编程时最后才需要考虑的问题之一 – 区别就在于这个问题够不上去同其它更加需要重点考虑的问题进行比较,比如说代码的清晰度和可读性. | leoxu 翻译于 2年前 1人顶 顶 翻译的不错哦! |
考虑到这一点,就有了如下的选择:
|
? |
? |
leoxu
翻译于 2年前
1人顶
顶 翻译的不错哦!
NSEnumerator 是循环遍历集合的一种可选方式. 所有的集合都已一个或者更多个枚举方法,每次它们被调用的时候都会返回一个NSEnumerator实体. 一个给定的 NSEnumerator 会包含一个指向集合中第一个对象的指针, 并且会有一个 nextObject 方法返回当前的对象并对指针进行增长. 你可以重复调用它直到它返回nil,这表明已经到了集合的末尾了: |
? |
leoxu
翻译于 2年前
0人顶
顶 翻译的不错哦!
快速枚举是在 Objective-C 2.0 中作为传统的NSEnumerator的更便利(并且明显更快速) 的替代方法而引入的. 它并没有使得枚举类过时因为其仍然被应用于注入反向枚举, 或者是当你需要对集合进行变更操作 (之后会更多地提到) 这些场景中. |
? |
? |
leoxu
翻译于 2年前
0人顶
顶 翻译的不错哦!
随着块的诞生,Apple加入第四个基于块语法的枚举机制. 这无疑比快速枚举更加的少见, 但是有一个优势就是对象和索引都会返回, 而其他的枚举方法只会返回对象. | leoxu 翻译于 2年前 0人顶 顶 翻译的不错哦! |
那么这些方法叠加起来会如何呢, 性能会更加的好么? 这里有一个简单的基准测试命令行应用,比较了使用多种不同方法枚举一个数据的性能. 我们已经在 ARC 关闭的情况下运行了它,以排除任何干扰最终结果的隐藏在幕后的保留或者排除处理. 由于是运行在一个很快的 Mac 机上面, 所有这些方法运行极快以至于我们实际上不得不使用一个存有10,000,000 (一千万) 对象的数组来测量结果. 如果你决定在一个 iPhone 进行测试, 最明智的做法是使用一个小得多的数量! |
? |
?
leoxu
翻译于 2年前
0人顶
顶 翻译的不错哦!
忽略掉时间的具体长短. 我们感兴趣的是它们同其它方法比较的相对大小. 如果我们按顺序排列它们,快的放前面,我会得到了下面的结果: For…in循环 – 最快. 对for循环的优化 – 比 for…in 慢两倍. 没有优化的for循环 – 比 for…in 慢2.5倍. Enumerator – 大约同没有优化的循环相同. 并发的枚举块 – 比 for…in 大约慢6倍. 枚举块 – 比 for…in 几乎慢6倍. For…in 是胜出者. 显然他们将其称为快速枚举是有原因的! 并发枚举看起来是比单线程的快一点点, 但是你没必要对其做更多的解读: 我们这里是在枚举一个非常非常大型的对象数组,而对于小一些的数据并发执行的开销远多于其带来的好处. 并发执行的主要是在当你的循环需要大量的执行时间时有优势. 如果你在自己的循环中有许多东西要运行,那就考虑试下并行枚举,在你不关心枚举顺序的前提下 (但是请用行动的去权衡一下它是否变得更快乐,不要空手去揣度). | leoxu 翻译于 2年前 0人顶 顶 翻译的不错哦! |
那么其它的结合类型怎么样呢, 比如 NSSet 和 NSDictionary? NSSet 是无序的, 因此没有按索引去取对象的概念.我们也可以进行一下基准测试: |
? |
leoxu
翻译于 2年前
0人顶
顶 翻译的不错哦!
NSDictionary 填充起来比 NSArray 或者 NSSet 慢得多, 因此我们把数据条数减少到了10,000 (一万) 以避免机器锁住. 因而你应该忽略结果怎么会比那些 NSArray 低那么多,因为我们使用的是更少对象的 1000 次循环: ? | leoxu 翻译于 2年前 0人顶 顶 翻译的不错哦! |
基于我们所见,如果所有其它的因素都一样的话,在循环遍历数组时你应该尝试去使用for...in循环, 而遍历字典时,则应该选择枚举块. 也有一些场景下这样的做法并不可能行得通,比如我们需要回头来进行枚举,或者当我们在遍历时想要变更集合的情况. |
? |
如果你想使用枚举块的话, NSEnumerationReverse你可以试试, 像这样:
? |
leoxu
翻译于 2年前
0人顶
顶 翻译的不错哦!
应用同样的循环技术到变更中的集合上是可能的; 其性能也大致相同. 然而当你尝试在循环数组或者字典的时候修改它们,你可能经常会面临这样的异常: | leoxu 翻译于 2年前 0人顶 顶 翻译的不错哦! |
我们仍然可以使用for…in, 但前提是我们首先创建了一个数组的拷贝. 这会起作用的,例如:
$ For loop: 0.111422 $ Optimized for loop: 0.08967 $ Enumerator: 0.313182 $ For…in loop: 0.203722 $ Enumeration block: 0.436741 $ Concurrent enumeration block: 0.388509 在我们遍历一个数组时修改这个数组最快的计数,似乎是需要使用一个优化了的for循环的. 对于一个 NSDictionary, 我们不需要为了使用NSEnumerator 或者快速枚举而复制整个字典; 我们可以只去使用allKeys方法获取到所有键的一个副本. 这都将能很好的运作起来:
| leoxu 翻译于 2年前 0人顶 顶 翻译的不错哦! |
然而同样的技术在使用enumerateKeysAndObjectsUsingBlock方法时并不能起作用. 如果我们循环遍历一个字典进行基准测试, 按照需要对键或者对字典整体创建备份,我们得到了下面的结果:$ For loop: 2.24597 $ Optimized for loop: 0.00282001 $ Enumerator: 0.00508499 $ For…in loop: 0.000990987 $ Enumeration block: 0.00144804 $ Concurrent enumeration block: 0.00166804 这里我们可以看到 for…in 循环是最快的一个. 那是因为在for...in循环中根据键取对象的开销现在已经被在调用枚举块方法之前复制字典的开销盖过去了. | leoxu 翻译于 2年前 0人顶 顶 翻译的不错哦! |
当枚举一个NSArray的时候: 使用 for (id object in array) 如果是顺序枚举 使用 for (id object in [array reverseObjectEnumerator]) 如果是倒序枚举 使用 for (NSInteger i = 0; i < count; i++) 如果你需要知道它的索引值,或者需要改变数组 尝试 [array enumerateObjectsWithOptions:usingBlock:] 如果你的代码受益于并行执行 当枚举一个NSSet的时候: 使用 for (id object in set) 大多数时候 使用 for (id object in [set copy]) 如果你需要修改集合(但是会很慢) 尝试 [array enumerateObjectsWithOptions:usingBlock:] 如果你的代码受益于并行执行 当枚举一个NSDictionary的时候: 使用 for (id object in set) 大多数时候 使用 for (id object in [set copy]) 如果你需要修改词典 尝试 [array enumerateObjectsWithOptions:usingBlock:] 如果你的代码受益于并行执行 这些方法可能不是最快的,但他们都是非常清晰易读的。所以请记住,有时是在不写干净的代码,和快速的代码之间做出选择,你会发现,你可以在两个世界得到最好的。 |
相关文章推荐
- QMetaObject::connectSlotsByName: No matching signal for问题的解决方法
- json字符串转换为JSONObject和JSONArray
- Runtime方法的使用—Object篇
- Android JsonObject 数据的遍历
- Object C基础学习(三)
- Java Object 的介绍
- juce 中的ReferenceCountedObjectPtr
- 使用Objective-C的文档生成工具:appledoc
- 速战速决 (2) - PHP: 数据类型 bool, int, float, string, object, array
- JAVA、PHP、C#、Object-C 通用的DES加密解密
- java.lang.Object
- Object-c------类的本质
- python 2.x和3.x关于 'module' object has no attribute 'open'的解决办法
- python 2.x和3.x关于 'module' object has no attribute 'open'的解决办法
- Realm的model终于可以不继承RealmObject了
- 一定要看的。深入理解Objective-C:Category
- Object-c------分类
- Objective-C中instancetype详解
- 属性遍历:in操作符/Object.keys()/ Object.getOwnPropertyNames()
- iOS使用Object-C自定义cordova插件(二)