何时使用NSEnumerationConcurrent

Chr*_*eux 13 concurrency cocoa objective-c grand-central-dispatch

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

所以我有一个特定的问题,一个更普遍的问题.

第一个问题:这是一个可能稍微有点人为的例子,它使用一个块同时做一些微不足道的事情:

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;
}
Run Code Online (Sandbox Code Playgroud)

忽略非并发枚举可能只是直接求和高度这一事实,而不需要调用malloc或函数的后半部分,在这里使用NSEnumerationConcurrent有什么意义吗?使用GCD(或任何NSEnumerationConcurrent在后台执行的操作)的开销是否会抵消同时获取平凡属性的收益?在使用NSEnumerationConcurrent值之前,块的工作需要多少微不足道的事情?

第二个问题:更一般地说,当我看到有机会这样做时,我应该考虑并发性(理论上:理论上这些API的重点是它们使并发性不是特殊情况而是更多部分的一般化妆一个程序),或者只是我应该使用的优化,如果我发现了一个特定的性能问题,并认为并发是答案(理由:并发代码中的错误是追踪的噩梦)?

bbu*_*bum 11

通常,当要执行的操作相对"繁重"时,您只使用并发.即使这样,enumerateObjectsWithOptions:如果并行性对于手头的任务来说是错误的粒度,那么使用提供的原始并发可能很容易成为问题.

GCD在排队和处理内容时非常有效,但该代码很可能最终会调用malloc()来复制块(取决于块是否具有唯一的捕获状态).

你的第二个问题的答案填补了许多书,大多数都没用.

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

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