What's the best way to set up concurrent execution of for loops in Objective C?

☆樱花仙子☆ 提交于 2019-12-08 12:10:23

问题


I have a situation with a time-intensive for loop like this:

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

The do something(i) calls are independent. This cries out for multithreading. Using NSOperationQueue on a two-core machine, I can do this:

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;

It would be much nicer to have a single NSBlock and pass the start/stop values for the loop as parameters, but blocks used with NSOperation cannot have parameters. One reason this would be nicer is that the gymnastics needed to code for varying numbers of cores gets pretty excessive.

Is there a better way to set this up in iOS so a single NSBlock (or its equivalent) can be created, with parameters, and then called multiple times for concurrent execution? The technique ideally needs to be local to the method, and have read/write access to local variables (which is possible with NSBlock using the __block qualifier on local variables)?


For those coming along afterwards, here's the code, gleaned from both answers and several comments, that I finally used.

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;
    });
});

回答1:


Use a concurrent dispatch queue.

    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
        });

    });



回答2:


You should probably use the NSEnumerationConcurren flag:

Let's say you had an array of objects you wanted to iterate through, you could do:

[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!

Using 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.
});


来源:https://stackoverflow.com/questions/24170706/whats-the-best-way-to-set-up-concurrent-execution-of-for-loops-in-objective-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!