在Objective C中设置for循环并发执行的最佳方法是什么?

时间:2014-06-11 19:07:24

标签: ios multithreading nsoperation nsoperationqueue

我遇到了这样一个时间密集的for循环:

int sum = 0;
for (int i = 0; i < max; ++i)
   sum += dosomething(i);

do something(i)次来电是独立的。这呼吁多线程。在双核机器上使用NSOperationQueue,我可以这样做:

int __block midpoint;
int __block sum1;
int __block sum2;
midpoint = max/2;
sum1 = 0;
sum2 = 0;

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

NSOperation *operation = [NSBlockOperation blockOperationWithBlock: ^{
    for (int i = 0; i < midpoint; ++i)
        sum1 += dosomething(i);
}];
[queue addOperation: operation];

operation = [NSBlockOperation blockOperationWithBlock: ^{
    for (int i = midpoint; i < lines.count; ++i)
        sum2 += dosomething(i);
}];
[queue addOperation: operation];

[queue waitUntilAllOperationsAreFinished];
int sum = sum1 + sum2;

使用单个NSBlock并将循环的开始/停止值作为参数传递会更好,但是与NSOperation一起使用的块不能有参数。更好的一个原因是,为不同数量的核心编码所需的体操变得相当过分。

有没有更好的方法在iOS中设置它,以便可以使用参数创建单个NSBlock(或其等效的),然后多次调用并发执行?理想情况下,该技术必须是方法的本地技术,并且具有对局部变量的读/写访问权限(使用局部变量上的__block限定符可以使用NSBlock)?


对于那些后来出现的人,这里是我最终使用的代码,从答案和几条评论中收集到的。

dispatch_queue_t coreQueue = dispatch_queue_create("coreQueue", DISPATCH_QUEUE_CONCURRENT);
int __block count = 0;
int processorCount = (int) [[NSProcessInfo processInfo] processorCount];

dispatch_apply(processorCount, coreQueue, ^(size_t i) {
    int localCount = 0;
    int imax = (i + 1)*max/processorCount;
    if (i + 1 == processorCount)
        imax = lines.count;
    int imin = i*max/processorCount;
    for (int j = imin; j < imax; ++j)
        localCount += dosomething(j);

    // The results array should only be accessed from the main queue.
    dispatch_async(dispatch_get_main_queue(), ^{
        count += localCount;
    });
});

2 个答案:

答案 0 :(得分:2)

您应该使用NSEnumerationConcurren标志:

假设您有一个想要迭代的对象数组,您可以这样做:

[myArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger idx, BOOL *stop) 
{

//do something

}];

Here's the apple documentation on NSEnumerationConcurrent

Here's a link to show how well it profiles!

使用dispatch_apply:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_apply(count, queue, ^(size_t i) {
printf("%u\n",i); //Do expensive operation here.
});

答案 1 :(得分:0)

使用并发调度队列。

    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        [self doAnExpensiveOperation];
    });
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        [self doAnotherExpensiveOperation];
    });
    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{

        dispatch_async(dispatch_get_main_queue(), ^{

            // called when both have finished.
            // calculate sum here
        });

    });