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_async
到 dispatch_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