问题与GCD和太多的线程

我有一个图像加载器类提供NSURL加载和图像从networking,并执行完成块。 代码其实很简单

- (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创build太多的线程吗? 我认为,gcd处理所有的treading,并确保线程的数量不是很大,但如果不是这样的话有什么办法可以影响线程数量?

那么从http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

并发队列(也称为全局调度队列)同时执行一个或多个任务,但是任务仍按其添加到队列中的顺序启动。 当前正在执行的任务在由调度队列pipe理的不同线程上运行。 在任何给定点执行的任务的确切数量是可变的,并取决于系统条件。

串行队列(也称为私有调度队列)按照将其添加到队列中的顺序一次执行一个任务。 当前正在执行的任务运行在由调度队列pipe理的不同线程上(可能因任务而异)。

通过调用所有的块到高优先级并发调度队列

 [NSData dataWithContentsOfURL:URL] 

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

您应该调度DISPATCH_QUEUE_PRIORITY_BACKGROUND 。 这些任务绝不是“高优先级”。 任何image processing都应该在有空闲时间的情况下完成,主线程上没有任何事情发生。

如果你想更多的控制这些事情一次发生,我build议你看看使用NSOperation 。 你可以把你的块和embedded到一个使用NSBlockOperation的操作,然后你可以提交这些操作到你自己的NSOperationQueue 。 一个NSOperationQueue有一个- (NSInteger)maxConcurrentOperationCount ,作为一个额外的好处,操作也可以在调度后取消,如果需要的话。

当全局并发队列的现有GCD工作线程的工作单元在内核中被阻塞很长一段时间时(只要全局队列上有进一步的工作挂起),内核就会创build额外的线程。

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

如果工作线程在内核中被阻塞的原因是IO(例如在本例中为+[NSData dataWithContentsOfURL:] ),最好的解决scheme是用一个将不会asynchronous执行该IO的APIreplaceNSURLConnection ,例如NSURLConnection for联网或为文件系统IO分派I / O。

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

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

您可以使用NSURLConnection支持的NSOperationqueue

它有以下实例方法:

 - (void)setMaxConcurrentOperationCount:(NSInteger)count