我一直在寻找一个类似的问题,但没有任何成功.我不知道如何优化cocoa中的一些代码来使用所有可用的CPU内核(我现在不想使用GPU).下面是简单的代码示例,我的意思是:
int limA = 1000; int limB = 1000; unsigned short tmp; for (int i = 0; i < 10000; i++) { for (int a = 0; a < limA; a++) { for (int b = 0; b < limB; b++) { tmp = [[array objectAtIndex:(a*b)] unsignedShortValue]; c_array[a*limB+b] += tmp; } } }
假设数组和c_array已正确初始化等...但正如您所看到的,如果我们有许多迭代(在这种情况下:10 ^ 10),则执行此代码需要一些时间.我想也许在几个线程中执行此代码很简单,但如何同步c_array?在objective-c中改善此类代码的时间执行的最佳方法是什么?也许它可以这样做,大多数外部for循环的迭代0-2499将在线程1和2500-4999线程2等执行...?我知道这是愚蠢的方式,但我不需要"实时"表现......任何想法?
一些建议:
对数组进行初始传递以从其对象包装器中提取所有短路:
short *tmp_array = calloc(limA * limB, sizeof(short)); int tmp_idx = 0; for (NSNumber *num in array) { tmp_array[tmp_idx++] = [num unsignedShortValue]; }
这有几个好处.你从10 ^ 10方法调用到10 ^ 6,你的内部循环停止对编译器不透明(它不能"透视"方法调用),你的内部循环变小,更有可能适合指令缓存.
尝试线性化访问模式.现在你正在进行"跨步"访问,因为索引每次都会成倍增加.如果您可以重新排列数据,tmp_array
以便按顺序处理的元素在数组中也是顺序的,那么您应该获得更好的性能(因为每次访问数组都会加载一个完整的缓存行,大多数处理器都是64字节).
从并行中获得好处可能很棘手.您可以尝试使用以下命令替换外部循环:
dispatch_apply(10000, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t i) { });
OSAtomicAdd
但是在内循环中+ = ,但我怀疑无论如何你的速度将由内存访问控制,并且在混合中添加更多处理器只会导致它们踩到彼此的脚趾(即处理器0加载c_array[1500]
所以它知道要添加什么tmp
,实际加载覆盖[1500-1531]的缓存行,然后处理器1写入c_array[1512]
,使整个缓存行无效并强制重新读取它.另外,我很确定你需要在c_array中存储32位值才能做到这一点,因为你将使用OSAtomicAdd32(没有OSAtomicAdd16).
至少,如果要进行并行化,那么您需要弄清楚如何将工作划分为32个元素c_array
(即64个字节)的非重叠块,以便您可以避免争用.划分数组的范围还应该让您避免需要使用原子添加操作.
(编辑)
查看an0的答案,找出并行化这个的一些实用建议,而不是讨论为什么天真的并行化不起作用:)