我正在学习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
个组件都将被阻止,直到:
我是对的吗?我知道,我们应该在这里使用UI
,我只是想知道事情是如何运作的。
2。问题)据我所知,所有全局队列都是并发队列,这意味着它可以通过上下文切换或并行来管理任务。但是,当我们通过dispatch_sync到达那个队列时,我们被迫等待,所有的工作都将完成。在这种情况下唯一不同于串行队列的是操作顺序。例如,如果串行队列有任务1,任务2,任务3和任务4,它将严格按顺序执行此操作,但并发队列可以更改它的顺序,以便首先完成轻量级操作。
所以,我的问题是,我们为什么要做 dispatch_async
?根据我的理解,主线程将被阻止,直到dispatch_sync
代码块完成。
答案 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()
并将后续代码作为继续步骤(或完成处理程序)放入任务中。但你不能总是这样做。