我有一个图像加载器类,它提供 NSURL 加载和来自网络的图像并执行完成 block 。代码其实很简单
- (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 个以上的线程。问题可能是我连续调用 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0) 50 次导致 GCD 创建了太多线程吗?我认为 gcd 处理所有的线程并确保线程数不是很大,但如果不是这样,我有什么办法可以影响线程数吗?
最佳答案
当全局并发队列的现有 GCD 工作线程上的工作单元在内核中被阻塞很长时间(只要全局队列上还有待处理的工作)时,内核会创建额外的线程。
这是必要的,这样应用程序才能继续取得整体进展(例如,执行一个挂起的 block 可能会允许阻塞的线程变得畅通无阻)。
如果工作线程在内核中被阻塞的原因是 IO(例如本例中的 +[NSData dataWithContentsOfURL:]
),最好的解决方案是用 API 替换这些调用异步执行该 IO 而不会阻塞,例如NSURLConnection
用于网络或文件系统 IO 的分派(dispatch) I/O。
或者,您可以手动限制并发阻塞操作的数量,例如通过使用计数调度信号量。
WWDC 2012 GCD session 详细讨论了这个主题。
关于ios - GCD 问题和线程过多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14685623/