objective-c - 何时使用 NSEnumerationConcurrent

标签 objective-c cocoa concurrency grand-central-dispatch

时不时地,我注意到我正在使用一个 block 来迭代一个集合,而不写入任何共享数据或导致任何副作用。我考虑添加一个 NSEnumerationConcurrent 选项,然后决定反对它,因为我真的不明白什么时候值得使用它。

所以我有一个具体的问题,还有一个更一般的问题。

第一个问题:这里有一个可能有点做作的例子,使用 block 来同时做一些微不足道的事情:

CGFloat GetAverageHeight(NSArray* people)
{
  NSUInteger count = [people count];
  CGFloat* heights = malloc(sizeof(CGFloat) * count);

  [people enumerateObjectsWithOptions: NSEnumerationConcurrent usingBlock:
  ^(id person, NSUInteger idx, BOOL* stop)
  {
    heights[idx] = [person height];
  }];

  CGFloat total= 0.0;
  for (size_t i = 0 ; i < count ; i++) total += heights[i];
  free(heights);
  return total / count;
}

忽略非并发枚举可以直接对高度求和的事实,而不需要调用 malloc 或函数的后半部分,在这里使用 NSEnumerationConcurrent 有什么意义吗?使用 GCD 的开销(或 NSEnumerationConcurrent 在后台所做的任何事情)是否抵消了同时获得一个微不足道的属性的好处?在值得使用 NSEnumerationConcurrent 之前,该 block 的工作需要减少多少?

第二个问题:更一般地说,当我看到有机会这样做时,我是否应该考虑并发性是我应该使用的东西(理由:这些 API 的要点大概是它们使并发性不再是特例,而更多地成为程序的一般构成),或者仅当我发现特定的性能问题并相信并发是答案时才应该使用的优化(基本原理:并发代码中的错误是追查的噩梦)?

最佳答案

通常,只有在要执行的操作相对“繁重”时才使用并发。即便如此,如果并行度对于手头的任务而言是错误的粒度,那么使用 enumerateObjectsWithOptions: 提供的原始并发性也很容易出现问题。

GCD 在排队和处理东西方面确实非常高效,但该代码很可能最终会调用 malloc() 来复制 block (取决于 block 是否具有唯一的捕获状态)。

你的第二个问题的答案写满了很多书,大部分都没用。

采用非并发代码并使其并发通常是一个非常困难的问题,充满了噩梦般的错误。然而,预先设计并发性可能会非常耗时。更糟糕的是,在没有实际使用的情况下实现 future 的并发只会在您打开它时导致噩梦般的调试体验。

一个关键点;在考虑并发性时,专注于使对象的整个子图线程隔离,以保存跨越线程/队列的定义非常明确的边界 API。核心数据就是一个很好的例子。

关于objective-c - 何时使用 NSEnumerationConcurrent,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6806930/

相关文章:

objective-c - 在 iPhone 上使用 FFMPeg 解码 WMA

ios - 调试问题 - 值被隐藏

objective-c - ios确定 subview 是否重叠( HitTest ?)

cocoa - 相同的 QtOpenGL 代码在使用 Carbon 时运行速度大约慢 15 倍(与 Cocoa 相比)

cocoa - NSTableView 覆盖

c# - 如何管理在 C# 中插入的并发性?

ios - 是否有可能读取 iOS 设备存储信息

cocoa - 文件被隐藏了吗?

python - ZeroMQ worker 应该如何安全地 "hang up"?

multithreading - F#:在异步返回之前 SwitchToThreadPool 的目的