GCD问题和线程太多

时间:2013-02-04 11:16:54

标签: ios multithreading grand-central-dispatch

我有一个图像加载器类,它提供了来自Web的NSURL加载和图像,并执行完成块。代码实际上很简单

- (void)downloadImageWithURL:(NSString *)URLString completion:(BELoadImageCompletionBlock)completion
{
    dispatch_async(_queue, ^{
//    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        UIImage *image = nil;
        NSURL *URL = [NSURL URLWithString:URLString];
        if (URL) {
            image = [UIImage imageWithData:[NSData dataWithContentsOfURL:URL]];
        }  
        dispatch_async(dispatch_get_main_queue(), ^{
            completion(image, URLString);
        });
    });

}

当我替换

dispatch_async(_queue, ^{

带注释

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

图像的加载速度要快得多,这是非常合乎逻辑的(之前一次加载一个图像,现在一堆图像同时加载)。我的问题是我可能有50个图像,我为所有这些调用downloadImageWithURL:completion:方法,当我使用全局队列而不是_queue时,我的应用程序最终崩溃,我看到有85个以上的线程。可能问题是我连续50次调用dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0)会让GCD创建太多线程吗?我认为gcd处理所有的treading并确保线程的数量不是很大,但如果不是这样的话,我有什么方法可以影响线程的数量?

3 个答案:

答案 0 :(得分:8)

当全局并发队列的现有GCD工作线程上的工作单元在内核中被阻塞了很长时间时(只要全局队列上还有待处理的工作),内核就会创建其他线程。

这是必要的,以便应用程序可以继续总体上取得进展(例如,其中一个挂起块的执行可能是阻止线程被解除阻塞的原因。)

如果在内核中阻止工作线程的原因是IO(例如本例中的+[NSData dataWithContentsOfURL:]),那么最好的解决方案是用API来替换这些调用,这些API将异步执行该IO而不会阻塞,例如: NSURLConnection用于网络或调度文件系统IO的I / O.

或者,您可以手动限制并发阻止操作的数量,例如通过使用计数调度信号量。

WWDC 2012 GCD会议详细讨论了这个主题。

答案 1 :(得分:2)

来自http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

  

并发队列(也称为一种全局调度队列)同时执行一个或多个任务,但任务仍在   它们被添加到队列的顺序。目前   执行任务在由...管理的不同线程上运行   调度队列。在任何给定点执行的确切任务数   是可变的,取决于系统条件。

  

串行队列(也称为私有调度队列)执行一项任务   按照它们添加到队列的顺序。该   当前执行的任务在不同的线程上运行(可能会有所不同)   从任务到任务)由调度队列管理。

通过

将所有块分派到高优先级并发调度队列
[NSData dataWithContentsOfURL:URL]

这是一个同步阻塞网络操作,它看起来像默认的GCD行为将产生一堆线程来尽快执行你的块。

您应该发送到DISPATCH_QUEUE_PRIORITY_BACKGROUND。这些任务绝不是“高优先级”。任何图像处理应该在有空闲时间时完成,并且主线程上没有任何事情发生。

如果您想要更多地控制一次发生这些事情的次数,我建议您考虑使用NSOperation。您可以使用NSBlockOperation获取块并将其嵌入到操作中,然后您可以将这些操作提交给您自己的NSOperationQueueNSOperationQueue有一个- (NSInteger)maxConcurrentOperationCount,如果需要,还可以在安排后取消操作。

答案 2 :(得分:1)

您可以使用NSOperationqueue

支持的NSURLConnection

它有以下实例方法:

- (void)setMaxConcurrentOperationCount:(NSInteger)count