我时不时地注意到,我使用块来迭代集合,而不会写入任何共享数据或导致任何副作用。我考虑添加 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;
}
忽略非并发枚举可以直接对高度求和,而不需要调用 malloc 或函数后半部分的事实,这里使用 NSEnumerationConcurrent 有什么意义吗?使用 GCD(或 NSEnumerationConcurrent 在后台执行的任何操作)的开销是否会抵消同时获取琐碎属性的收益?在值得使用 NSEnumerationConcurrent 之前,块的工作需要变得不那么琐碎吗?
第二个问题:更一般地说,当我看到有机会这样做时,我是否应该考虑使用并发性(理由:大概这些 API 的目的是它们使并发性不再是一种特殊情况,而更多地成为一般构成的一部分)程序的一部分),或者只是一种优化,只有在我发现特定的性能问题并相信并发是答案时才应该使用(理由:并发代码中的错误是追踪的噩梦)?
一般来说,只有当要执行的操作相对“繁重”时,您才会使用并发。即使如此,使用提供的原始并发性enumerateObjectsWithOptions:
如果并行性对于手头的任务来说是错误的粒度,那么很容易出现问题。
GCD 在排队和处理内容方面确实非常高效,但该代码很可能最终会调用 malloc() 来复制块(取决于该块是否具有唯一的捕获状态)。
你的第二个问题的答案写满了很多书,但大多毫无用处。
获取非并发代码并使其并发通常是一个非常困难的问题,充满了噩梦般的错误。然而,预先设计并发性可能会非常耗时。更糟糕的是,在没有实际使用它的情况下实现未来的并发性只会在您打开它时导致噩梦般的调试体验。
一个关键点;在考虑并发性时,重点关注使对象的整个子图线程隔离,以保存跨线程/队列的定义非常明确的边界 API。核心数据就是一个很好的例子。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)