我有一个图像加载器类,它提供了来自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并确保线程的数量不是很大,但如果不是这样的话,我有什么方法可以影响线程的数量?
答案 0 :(得分:8)
当全局并发队列的现有GCD工作线程上的工作单元在内核中被阻塞了很长时间时(只要全局队列上还有待处理的工作),内核就会创建其他线程。
这是必要的,以便应用程序可以继续总体上取得进展(例如,其中一个挂起块的执行可能是阻止线程被解除阻塞的原因。)
如果在内核中阻止工作线程的原因是IO(例如本例中的+[NSData dataWithContentsOfURL:]
),那么最好的解决方案是用API来替换这些调用,这些API将异步执行该IO而不会阻塞,例如: NSURLConnection
用于网络或调度文件系统IO的I / O.
或者,您可以手动限制并发阻止操作的数量,例如通过使用计数调度信号量。
WWDC 2012 GCD会议详细讨论了这个主题。
答案 1 :(得分:2)
并发队列(也称为一种全局调度队列)同时执行一个或多个任务,但任务仍在 它们被添加到队列的顺序。目前 执行任务在由...管理的不同线程上运行 调度队列。在任何给定点执行的确切任务数 是可变的,取决于系统条件。
和
串行队列(也称为私有调度队列)执行一项任务 按照它们添加到队列的顺序。该 当前执行的任务在不同的线程上运行(可能会有所不同) 从任务到任务)由调度队列管理。
通过
将所有块分派到高优先级并发调度队列[NSData dataWithContentsOfURL:URL]
这是一个同步阻塞网络操作,它看起来像默认的GCD行为将产生一堆线程来尽快执行你的块。
您应该发送到DISPATCH_QUEUE_PRIORITY_BACKGROUND
。这些任务绝不是“高优先级”。任何图像处理应该在有空闲时间时完成,并且主线程上没有任何事情发生。
如果您想要更多地控制一次发生这些事情的次数,我建议您考虑使用NSOperation
。您可以使用NSBlockOperation
获取块并将其嵌入到操作中,然后您可以将这些操作提交给您自己的NSOperationQueue
。 NSOperationQueue
有一个- (NSInteger)maxConcurrentOperationCount
,如果需要,还可以在安排后取消操作。
答案 2 :(得分:1)
您可以使用NSOperationqueue
NSURLConnection
它有以下实例方法:
- (void)setMaxConcurrentOperationCount:(NSInteger)count