了解dispatch_async

时间:2013-04-29 16:27:54

标签: objective-c asynchronous dispatch-async

我对此代码有疑问

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSData* data = [NSData dataWithContentsOfURL: 
      kLatestKivaLoansURL];
    [self performSelectorOnMainThread:@selector(fetchedData:) 
      withObject:data waitUntilDone:YES];
});

此代码的第一个参数是

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 

我们是否要求此代码在全局队列上执行串行任务,其定义本身是返回给定优先级的全局并发队列?

在主队列上使用dispatch_get_global_queue有什么好处?

我很困惑。能帮助我更好地理解这一点。

3 个答案:

答案 0 :(得分:495)

在主队列中使用默认队列的主要原因是在后台运行任务。

例如,如果我从互联网上下载文件并且我想更新用户下载的进度,我将在优先级默认队列中运行下载并异步更新主队列中的UI。 / p>

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    //Background Thread
    dispatch_async(dispatch_get_main_queue(), ^(void){
        //Run UI Updates
    });
});

答案 1 :(得分:194)

所有DISPATCH_QUEUE_PRIORITY_X队列都是并发队列(意味着它们可以同时执行多个任务),并且在某种意义上,FIFO是指使用“先进先出”顺序开始执行给定队列中的任务。这与主队列(来自dispatch_get_main_queue())相比,后者是一个串行队列(任务将按接收顺序开始执行并完成执行)。

因此,如果向DISPATCH_QUEUE_PRIORITY_DEFAULT发送1000个dispatch_async()块,那么这些任务将按照您将它们发送到队列的顺序开始执行。同样适用于HIGH,LOW和BACKGROUND队列。您发送到任何这些队列的任何内容都将在后台执行,在远离主应用程序线程的备用线程上执行。因此,这些队列适用于执行后台下载,压缩,计算等任务。

请注意,执行顺序是每个队列的FIFO。因此,如果您将1000个dispatch_async()任务发送到四个不同的并发队列,均匀分割​​它们并按顺序将它们发送到BACKGROUND,LOW,DEFAULT和HIGH(即您在HIGH队列中安排最后250个任务),很可能是你看到的第一个任务就是在HIGH队列中,因为系统已经暗示这些任务需要尽快到达CPU。

另请注意,我说“将按顺序开始执行”,但请记住,作为并发队列,事物不一定按顺序执行,具体取决于每个任务的时间长度。

根据Apple:

https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

  

当您有多个可并行运行的任务时,并发调度队列非常有用。并发队列仍然是一个队列,因为它以先进先出的顺序将任务队列化;但是,并发队列可能会在任何先前任务完成之前将其他任务出列。并发队列在任何给定时刻执行的实际任务数是可变的,并且可以随着应用程序中的条件的变化而动态变化。许多因素会影响并发队列执行的任务数,包括可用核心数,其他进程正在完成的工作量,以及其他串行调度队列中任务的数量和优先级。

基本上,如果您将这1000个dispatch_async()块发送到DEFAULT,HIGH,LOW或BACKGROUND队列,它们将按您发送的顺序开始执行。但是,较短的任务可能在较长的任务之前完成这背后的原因是,如果有可用的CPU核心,或者当前队列任务正在执行计算上非密集型工作(从而使系统认为它可以并行分派其他任务而不管核心数量)。

并发级别完全由系统处理,并且基于系统负载和其他内部确定的因素。这是Grand Central Dispatch(dispatch_async()系统)的美妙之处 - 您只需将工作单元作为代码块,为它们设置优先级(基于您选择的队列)并让系统处理其余部分。

所以回答你的上述问题:你是部分正确的。您“要求该代码”在指定优先级的全局并发队列上执行并发任务。块中的代码将在后台执行,任何其他(类似)代码将潜在并行执行,具体取决于系统对可用资源的评估。

另一方面,“main”队列(来自dispatch_get_main_queue())是一个串行队列(不是并发)。发送到主队列的任务将始终按顺序执行,并始终按顺序完成。这些任务也将在UI线程上执行,因此它适用于使用进度消息,完成通知等更新UI。

答案 2 :(得分:29)

Swift版本

这是David的Objective-C答案的Swift版本。您可以使用全局队列在后台运行事物,使用主队列来更新UI。

Swift 3

DispatchQueue.global(qos: .background).async {

    // Background Thread

    DispatchQueue.main.async {
        // Run UI Updates
    }
}