Objective C — 枚举数组最快和最有效的方法是啥?

Posted

技术标签:

【中文标题】Objective C — 枚举数组最快和最有效的方法是啥?【英文标题】:Objective C — What is the fastest and most efficient way to enumerate an array?Objective C — 枚举数组最快和最有效的方法是什么? 【发布时间】:2011-09-05 22:06:47 【问题描述】:

编辑

我阅读了一些关于块和快速枚举以及 GCD 之类的文章。 @Bbum 写了很多关于 GCD 和块主题的文章,他说块枚举方法总是比快速枚举等效方法快或快。你可以阅读他的推理here。

虽然这是一次引人入胜的智慧对话,但我同意那些说这真的取决于手头的任务的人的观点。


我有一些任务要完成,我需要快速、廉价且高效地完成它们。 Apple 为我们提供了许多选择来枚举数组的方式,但我不确定该选择哪一个。

快速枚举

for (id obj in array)

    /* Do something with |obj|. */

非并发块枚举

[array enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) 
    /* Do something with |obj|. */
];

并发块枚举

[array enumerateObjectsWithOptions: NSEnumerationConcurrent usingBlock: ^(id obj, NSUInteger idx, BOOL *stop) 
    /* Do something with |obj|. */
];

GCD 应用

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_apply([array count], queue, ^(size_t idx) 
    id obj = [array objectAtIndex: idx];
    /* Do something with |obj|. */
);

GCD 异步应用

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^(void) 
    dispatch_apply([array count], queue, ^(size_t idx) 
        id obj = [array objectAtIndex: idx];
        /* Do something with |obj|. */
    );
);

或者可能是NSBlockOperations 或NSOperationQueue

TIA,亚历克斯。

【问题讨论】:

你能比较异步和非异步调用吗? “高效”的标准是什么? “便宜”和“快”一样重要吗?等等... :) 如果有更多关于您的特定场景的信息可能会有所帮助? 另见***.com/questions/992901/…。 那我可以比较一下是什么意思?我在 ios 上执行此枚举,因此它需要高效且快速,但相同的一般概念也应适用于 Mac OS X。就 iOS 而言,你的资源更少,所以我试图尽可能提高效率。就是这样。 您的问题没有单一、绝对的答案。我投票关闭它。 基准,基准,基准,基准,基准。然后再做一次。 【参考方案1】:

最快的代码是最先进入市场的代码。

说真的——除非你有一个可衡量的性能问题,否则这个特定的选择应该不会占用你更多的时间来回答这些模式中的哪一个最自然地符合我的项目风格?

注意:通过从串行执行转移到并发执行来解决性能问题通常会导致两个问题;性能和并发性。

【讨论】:

【参考方案2】:

这真的取决于手头的任务。

一次处理多个迭代需要产生线程。如果迭代中的逻辑是可并行化的并且花费的时间比产生线程所花费的时间多,那么使用线程。此外,如果数组中有很多项,生成一个线程比遍历整个数组所需的时间更少,请将您的数组分成几部分并并行处理。

否则,生成线程来遍历数组是开销。即使操作系统为您处理了这些问题,它仍然确实需要生成它们。这需要时间和资源以及运行时的上下文切换(取决于可用的 CPU 数量、负载、调度程序等)。

这一切都归结为产生一个新线程是否比遍历整个数组需要更长的时间。您可以使用分析工具找到它。

【讨论】:

这是真的。我想我应该尝试所有这些,看看哪个最快。 另外,不要假设如果它对您当前的阵列来说是最快的,那么对于下一个阵列也是如此。如果你有一个包含 10 个整数的数组并且你需要做的就是将它们相加,那么显然最快的方法就是简单地使用for,即使包含重物的百万项数组从 GCD 方法中受益匪浅。跨度> 再一次,根据具体情况,最好将您的数组划分为可以并行处理的较小数组。例如,如果您只有 20 个需要时间来处理的对象,那么如果您并行处理 2 个包含 10 个对象的数组,则可能会比您创建 20 个线程时获得更好的性能。个人资料。 再一次,根据对数组元素执行的操作,GCD 可能是一个问题——例如,如果操作是阻塞的,它可能会导致 GCD 达到 GCD 线程的最大数量。变量太多,无法给出绝对答案。 让 GCD 快速的一件事是它不必为每个新任务创建线程,而是将任务分派到现有线程。【参考方案3】:

如果您观看 WWDC 视频“隐藏的 iOS7 中的开发宝石”(这个问题比授予的视频更早),您会发现使用 GCD 可以更好地实现简单的 for 循环枚举:

[array enumerateObjectsWithOptions: NSEnumerationConcurrent usingBlock: ^(id obj, NSUInteger idx, BOOL *stop) /* Do something with |obj|. */ ];

虽然它在一定程度上确实取决于手头的任务,并且交付软件是最重要的,但当您的应用程序开始扩展时,绝对有一些简单的方法可以防止性能问题在未来作为技术债务问题出现.例如,您可能有一个大型网络获取结果。从这个结果中,您可能必须遍历获取的对象并更新某些模型或模型系列(不是 Core Data 模型,因为 Core Data 不是线程安全的!必须采取其他措施才能在多个线程上使用 Core Data。这是如果您正在考虑从多线程场景中处理 Core Data,您将需要研究一个深入的主题)。考虑到您没有对 UI 执行更新(因为这不是您希望在主线程之外执行的操作),您可以使用此方法来充分利用设备的硬件。与一次仅使用一个内核的 for 循环不同,它将充分利用并行可用的内核,从而提高性能并可能将执行时间几乎减半。如果不考虑您正在枚举的数组以及您在块内执行的任务,这不是您想要做的事情,但如果仔细使用,它对各种情况都很有用。

【讨论】:

因此,由于您认为我提供了潜在危险的信息,因此您对 Apple 自己的布道者提供的信息支持的答案投了反对票。问题是要求照明,这正是我提供的内容以及我从何处获得所述信息的参考。下次当你觉得有必要写一个糟糕的连续句子评论来批评一个答案时,一定要包括你批评的确切原因。潜在危害?困惑?不,他想快速而廉价地循环遍历一个数组。观看视频。这正是福音传道者对此的建议。 “虽然它在一定程度上取决于手头的任务” -caveat “如果你观看了 WWDC 视频“隐藏的 iOS7 中的开发宝石””——在哪里可以找到进一步的解释 所以请在答案中提供进一步的解释,而不是指出视频。使用有关此枚举为何对您有用的属性信息编辑您的答案,我将收回我的反对票。 让我们continue this discussion in chat

以上是关于Objective C — 枚举数组最快和最有效的方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Java中最快和最有效的音频上采样例程

当您在 LAMP 服务器上拥有数百万用户时,存储和获取图像的最快和最有效的方法是啥?

重置多维数组的最快方法?

获取数组第一项的最快方法是啥? [复制]

如何限制Objective C中枚举值的可见性?

按二维排序 NSArray - Objective-C