了解dispatch_sync和全局队列

时间:2015-07-11 20:25:15

标签: ios objective-c multithreading

我正在学习GCD机制,我有几个问题。如果你纠正我,我会很感激,如果我出错了。

1。问题)据我所知,GCD有4个全局并发队列,具有不同的优先级。例如,当我们写var startTime = DateTime.Now; await Next.Invoke(context); var endTime = DateTime.Now; Duration = endTime - startTime; 时,我们会得到其中一个队列。 队列不是空的,一些Apple系统进程在它们上面运行。因此,当我们在某个队列中添加代码块时,例如,当n是随机整数时,它可能是一行中的n个数字任务。

现在,当我们添加代码块时,比如

DISPATCH_QUEUE_PRIORITY_HIGH
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ // Heavy calculations });

,所有viewDidLoad个组件都将被阻止,直到:

  1. Apple系统任务将完成(因为我们在该队列中最后添加任务,应该等到其他系统任务完成)
  2. 直到我们的代码完成。
  3. 我是对的吗?我知道,我们应该在这里使用UI,我只是想知道事情是如何运作的。

    2。问题)据我所知,所有全局队列都是并发队列,这意味着它可以通过上下文切换或并行来管理任务。但是,当我们通过dispatch_sync到达那个队列时,我们被迫等待,所有的工作都将完成。在这种情况下唯一不同于串行队列的是操作顺序。例如,如果串行队列有任务1,任务2,任务3和任务4,它将严格按顺序执行此操作,但并发队列可以更改它的顺序,以便首先完成轻量级操作。

    所以,我的问题是,我们为什么要做 dispatch_async ?根据我的理解,主线程将被阻止,直到dispatch_sync代码块完成。

1 个答案:

答案 0 :(得分:13)

  

GCD有4个全局并发队列,具有不同的优先级。例如,当我们写DISPATCH_QUEUE_PRIORITY_HIGH时,我们会得到其中一个队列。这些队列不是空的,一些Apple系统进程在它们上面运行。

在任何给定时间,队列可能是空的,也可能不是。没有办法知道。是的,框架可能会像代码一样向这些队列添加内容。

但是队列不会运行。队列是一种数据结构。它按顺序执行任务。 GCD根据需要管理一组工作线程,创建新线程或让它们退出。这些工作线程将任务从队列中取出并执行它们。

  

当我们添加代码块时,比如

dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

      // Heavy calculations

  });
     

viewDidLoad中,所有UI个组件都会被阻止,直到:1 - Apple   系统任务将完成(因为我们在最后添加我们的任务   队列,应该等到其他系统任务完成)2 - 直到我们的   代码将完成。

顾名思义,dispatch_sync()是同步的。这意味着它在完成它被要求做的工作(你通过的块)之前不会返回。是否必须等待队列中的任何其他任务取决于可用的系统资源。正如您所指出的那样,队列是并发的,因此可以将任务拉出并同时运行。如果有足够的可用CPU核心,GCD可以启动足够的工作线程来同时运行队列中的所有任务。因此,您的任务不必等待其他任务完成,只需要等待那些任务已经启动(从队列的头部弹出)并且有一个备用工人线程可用。

如果所有系统资源(如CPU核心)都忙,您只需等待其他任务完成。

  

据我所知,所有全局队列都是并发队列,这意味着它可以通过上下文切换或并行来管理任务。但是,当我们通过dispatch_sync到达那个队列时,我们被迫等待,所有的工作都将完成。

不,这是错的,正如我上面所解释的那样。您知道的唯一事情必须在dispatch_sync()返回之前完成,这是您使用它提交的一项任务。除非所有CPU核心都忙,否则它不必等待该队列上的任何其他任务。

  

在这种情况下唯一不同于串行队列的是操作顺序。例如,如果串行队列有任务1,任务2,任务3和任务4,它将严格按顺序执行此操作,但并发队列可以更改它的顺序,以便首先完成轻量级操作。

没有。并发队列严格按顺序启动操作,就像串行队列一样。只是串行队列才会启动另一个操作,直到当前的一个操作完成。全局并发队列将允许其所有操作同时启动和运行,直至可用资源。队列无法知道操作是否轻量级。

  

所以,我的问题是,我们为什么要做dispatch_sync?根据我的理解,主线程将被阻止,直到dispach_sync代码块完成。

并发和同步行为是两个独立的概念。同步与异步确定调用者的行为。它确定在工作完成之前是否允许调用者继续。

Concurrent vs. serial确定如何运行提交的任务。并发队列允许任务彼此同时运行。串行队列只允许其中一个任务一次运行。

从主线程调用dispatch_sync()是有意义的,但你必须要小心。例如,当使用串行队列来同步对多个线程共享的数据结构的访问时,可能是必要的。一般规则是您需要避免长时间阻塞主线程。如果您有充分的理由相信它会在很短的时间内被用户无法察觉,那么可以阻止它。

你肯定不想在主线程中使用dispatch_sync()进行“重计算”,就像你说的那样。

通常,在您需要完成任务之前使用dispatch_sync(),然后才能继续。通常,您可以重构代码,而不是使用dispatch_async()并将后续代码作为继续步骤(或完成处理程序)放入任务中。但你不能总是这样做。