dispatch_get_global_queue vs dispatch_get_main_queue

Posted

技术标签:

【中文标题】dispatch_get_global_queue vs dispatch_get_main_queue【英文标题】: 【发布时间】:2012-09-23 11:28:33 【问题描述】:

开始学习核心数据和 dispatch_async。有一段代码可以从一组数据中获取图像的 url 并将其设置为核心数据的模型,如下所示

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
                NSString *urlString = [[[photoDictionary valueForKey:@"images"] objectAtIndex:0] valueForKey:@"url"];
                NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
                dispatch_async(dispatch_get_main_queue(), ^
                    [photoModel setValue:imageData forKey:@"photoImageData"];

谁能向我解释为什么我们使用dispatch_get_global_queue 用于外部dispatch_async 和dispatch_get_main_queue 用于内部dispatch_async。

【问题讨论】:

【参考方案1】:

dispatch_get_global_queue(Swift 中的DispatchQueue.global())为您提供了一个后台队列,您可以在该队列上调度异步运行的后台任务(即不会阻塞您的用户界面)。如果您最终将多个块提交到全局队列,这些作业可以同时运行。如果您有多个代码块要提交到必须在后台按顺序运行的后台队列(不经常需要),您可以创建自己的串行后台队列并分派到该队列,但如果并发后台操作是可以接受,然后使用dispatch_get_global_queue 方便/高效。

但请注意,您不能在后台队列中执行用户界面更新,因此 dispatch_asyncdispatch_get_main_queue(即 Swift 中的 DispatchQueue.main.async ... )允许后台队列调度用户界面一旦主队列可用,就会更新回主队列。

这是一种非常常见的编程模式:提交一些东西在后台运行,当它需要执行用户更新时,将更新分派回主队列。

有关详细信息,请参阅Concurrency Programming Guide。

【讨论】:

进一步注意:不建议在全局队列上阻塞 IO,因为全局队列的线程限制非常低(64 个线程)。一旦所有可用线程在 IO 上被阻塞,您程序中其他地方的任何工作,包括在系统框架中使用全局队列的工作都将停止。 系统应该通过各种私有机制保护自己免受这种情况的影响,但这在过去一直是个问题。即使框架中的每个人都在做正确的事情,为什么还要有 64 个线程?那只是浪费。 我可能会改写一下。它比“阻塞 IO”更通用。这是任何可能“等待”的东西。但是,如果你有太多的 GCD 工作线程可能会耗尽非常有限的 GCD 工作线程,这只是一个实际问题。请参阅 WWDC 2015 video 或 2016 video 中的“线程爆炸导致死锁”讨论。在这类场景中,我们经常使用OperationQueue 及其maxConcurrentOperationCount 或其他类似模式。【参考方案2】:

dispatch_get_main_queue 应该在您想要操作 UI 元素的任何时候使用。这与线程亲和性有关,这是 UI 框架的常见模型。线程关联意味着您只能在创建该对象的线程上操作该对象。对于 Cocoa Touch 中的 UI 类,这是主线程。这是所有重要平台上的 UI 框架的典型习语。

所以dispatch_get_main_queue 获取与主线程关联的队列。当你的 UI 在不同的线程上更新时,不这样做会导致奇怪的事情发生。我通常会看到 UI 冻结的长时间停顿。

dispatch_get_global_queue 获取与您的应用关联的给定优先级的任何旧队列。非常适合网络调用,或者在您的情况下使用 Core Data。

【讨论】:

【参考方案3】:

全局队列为您提供主队列以外的队列,但省去了实际创建自己的队列的麻烦。当你需要你的代码在主队列上工作时使用 get_main_queue(你的所有 UI 工作都需要在这里进行)

【讨论】:

【参考方案4】:
**dispatch_get_main_queue** :- Perform UI updates on this queue

 dispatch_async(dispatch_get_main_queue(), ^


self.label.text=@"Hello";

    );

**dispatch_get_main_queue**:- Perform background tasks like downloading content

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
    for (int i=0; i<100000;enter code here i++) 
        NSLog(@"HIGH 1 %d", i);
    
);

【讨论】:

您将优先级值传递给第一个标识符参数。旗帜排在第二位:) 如果有人还在看这个线程,我正在尝试在更新标签文本的 main_queue 区域中进行 CGRect 绘制线条和圆圈。但我得到的上下文为零。如果我尝试将其设为同步队列,它就会爆炸。有什么想法吗?【参考方案5】:

简而言之,dispatch_get_global_queue 用于执行后台任务。但是当您在后台执行任何任务时,如果您需要执行与user interface相关的任何任务,则需要在dispatch_get_main_queue()中执行

【讨论】:

以上是关于dispatch_get_global_queue vs dispatch_get_main_queue的主要内容,如果未能解决你的问题,请参考以下文章

GCD中的dispatch_get_global_queue(long identifier, unsigned long flags)

dispatch_get_global_queue vs dispatch_get_main_queue

在 ios 7(swift) 上使用 dispatch_get_global_queue 时发生 EXC_BAD_INSTRUCTION

gcd 控制线程执行顺序(供参考)

dispatch_sync和dispatch_async的区别

异步汇合