同时执行多个方法的最快方法

时间:2012-06-01 09:13:01

标签: iphone objective-c ios asynchronous

我有4个方法,每个方法在方法返回之前需要一两秒钟,这些方法返回UIImage,我需要这些图像以最快的方式显示。

-(NSMutableArray*)prepareImages{
  UIImage *imageToModifyUsingUIImageCategory;

  NSMutableArray *imageArray = [[NSMutableArray alloc]initWithObjects:
  [imageToModifyUsingUIImageCategory doSomethingAndReturn1],
  [imageToModifyUsingUIImageCategory doSomethingAndReturn2],
  [imageToModifyUsingUIImageCategory doSomethingAndReturn3],
  [imageToModifyUsingUIImageCategory doSomethingAndReturn4],nil];    
  return imageArray;
}

在上面的方法结束时,我将从该数组中获得4个图像。每个“doSomethingAndReturn”方法需要一两秒,这意味着我的prepareImages方法将完成大约5秒的执行。太久了吧?

我的问题是,还有什么方法可以更快地完成所有这些? GCD是我的选择吗?如何?

非常感谢任何帮助。谢谢!

5 个答案:

答案 0 :(得分:16)

假设您不介意在后台顺序加载图像(而不是并行加载),只需简单地调度后台队列即可运行prepareImages

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    NSArray *images = [self prepareImages];

    // now send the result back to the main thread so we can do
    // UIKit stuff
    dispatch_async(dispatch_get_main_queue(), ^{
        // set the images on your UIImageViews here...
    });
});

这会将图像加载到低优先级后台队列中,然后在完成后调度回主线程。

如果您希望保持较低的优先级,可以使用DISPATCH_QUEUE_PRIORITY_BACKGROUND,但这仅适用于iOS 4.3及更高版本。在这种情况下,您应该检查dispatch_get_global_queue的返回值,如果它返回0,您可以回退其他优先级之一。

如果要并行加载每个图像,您应该将doSomethingAndReturn方法转换为NSOperation子类,并使用NSOperationQueue来运行它们。这需要更多的努力来实施。如果一次处理多个大图像,请注意内存使用情况。

答案 1 :(得分:1)

我知道如何解决,但尚未经过测试。我正在从我遇到并解决的其他几个问题中得出解决方案:

  • NSNull插入NSMutableArray作为占位符。
  • dispatch_async繁重的工作并替换NSMutableArray中的相应条目(使用@synchronized关键字锁定NSMutableArray
  • 同样在dispatch async函数中,向主队列发送更新视图的功能。

答案 2 :(得分:1)

您可以使用NSOperationQueue

  

NSOperationQueue类调节一组NSOperation对象的执行。添加到队列后,操作将保留在该队列中,直到明确取消或完成其任务为止。队列内的操作(​​但尚未执行)本身根据优先级和操作间对象依赖性进行组织,并相应地执行。应用程序可以创建多个操作队列并向其中任何一个提交操作。

example for a NSOperationQueue imeplementation

GCD Queue

  

Grand Central Dispatch(GCD)调度队列是执行任务的强大工具。通过调度队列,您可以相对于调用者异步或同步地执行任意代码块。您可以使用调度队列执行几乎所有在单独线程上执行的任务。调度队列的优点是它们比相应的线程代码更易于使用,并且执行这些任务的效率更高。

example for a GCD Queue implementation

答案 3 :(得分:1)

您可以在处理器的另一个核心上同时执行以尝试:

NSThread detachNewThreadSelector:@selector(YOUR_METHODS_HERE:) toTarget:self withObject:nil];
NSThread detachNewThreadSelector:@selector(YOUR_METHODS_HERE:) toTarget:self withObject:nil];
NSThread detachNewThreadSelector:@selector(YOUR_METHODS_HERE:) toTarget:self withObject:nil];
NSThread detachNewThreadSelector:@selector(YOUR_METHODS_HERE:) toTarget:self withObject:nil];

如果您的处理器有四个核心,则每个方法将在不同的核心上执行。

答案 4 :(得分:0)

我只是将它作为练习:对每个doSomethingAndReturn使用GCD并发Q并使用序列q来监视回调的数量。当回调数等于doSomethingAndReturn(s)的数量时,则返回prepareImages数组。

我创建了代码来测试这个概念。

-(NSString *)doSomethingAndReturn1
{
    for (int i=0; i<30; i++) 
    {
        NSLog(@"soSomethingAndReturn1 i: %i", i);
    }
    return @"soSomethingAndReturn1";
}

-(NSString *)doSomethingAndReturn2
{
    for (int i=0; i<10; i++) 
    {
        NSLog(@"soSomethingAndReturn2 i: %i", i);
    }
    return @"soSomethingAndReturn2";
}

-(NSString *)doSomethingAndReturn3
{
    for (int i=0; i<20; i++) 
    {
        NSLog(@"soSomethingAndReturn3 i: %i", i);
    }
    return @"soSomethingAndReturn3";
}

-(void)addToArray:(NSString *)str
{
    [asyncArray addObject:str];
    NSLog(@"asyncArray: %@", asyncArray);
}

- (IBAction)buttonMultitasksPressed:(id)sender 
{
    dispatch_queue_t serialdQueue;
    serialdQueue = dispatch_queue_create("com.mydomain.testbed.multimethods", NULL);
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self addToArray:[self doSomethingAndReturn1]];
        });
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self addToArray:[self doSomethingAndReturn2]];
        });
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self addToArray:[self doSomethingAndReturn3]];
        });
        dispatch_sync(serialdQueue, ^{
            while (!([asyncArray count] == 3)) 
            {
                NSLog(@"not there yet count: %i", [asyncArray count]);
            }
        });

    NSLog(@"end of dispatch_sync serialQueue");
//    return asyncArray;
}

编辑:第二个想法:不需要序列号。