问题与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,并确保线程的数量不是很大,但如果不是这样的话有什么办法可以影响线程数量?
并发队列(也称为全局调度队列)同时执行一个或多个任务,但是任务仍按其添加到队列中的顺序启动。 当前正在执行的任务在由调度队列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
- GCD和外部线程
- Swift 3:DispatchQueue.main.async {}和DispatcQueue.main.async之间的区别(execute:{})?
- 你可以用GCD / dispatch_async使用cancel / isCancelled吗?
- 由于等待,dispatch_semaphore_signal从不被执行
- 苹果文档的GCD生产者 – 消费者解决scheme错误?
- 全局队列中的定时器不在iOS中调用
- 如何在iOS中在后台运行NSURLConnection
- 在dispatch_semaphore_dispose上的EXC_BAD_INSTRUCTION(code = EXC_I386_INVOP,子码= 0x0)
- dispatch_async超时方法调用