ios - GCD 问题和线程过多

标签 ios multithreading grand-central-dispatch

我有一个图像加载器类,它提供 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/

相关文章:

ios - UITapGestureRecognizer 和 UIButton = EXC_BAD_ACCESS

ios - 如何将普通的CGRectMake转换成单位坐标?

ios - uiview 动画在动画制作过程中添加加速

c# - WaitAll 构造中单个线程的性能测量

objective-c - 除非与 NSRunLoop 一起使用,否则 dispatch_group_wait 不会按预期运行?

ios - 与主线程相比,何时应异步执行任务?

ios - 在 iphone xcode 中存储经纬度的最佳和最精确的数据类型是什么?

java - Spring MVC : How do I store an application scoped key-value map (considering thread-safety)?

.net - 惰性单线程 worker

ios - 加载 UIImagePickerController 更快?