Swift中DispatchQueue类型的区别

8
据我了解,在 Swift 中有 3 种 DispatchQueue 类型:
- Main (串行) (主线程) - Global (并发) (在后台线程中并行工作) - Custom (并发或串行)
每个队列都可以是异步或同步的。 第一个问题: Main 队列只在 UI 线程上工作而不在其他线程上工作吗?如果答案是肯定的,那么 DispatchQueue.Main.async 如何不会阻塞 UI 线程?如果答案是否定的,那么使用 DispatchQueue.global 的好处是什么,因为 DispatchQueue.Main.async 在另一个线程中工作。 第二个问题: DispatchQueue.global (async)DispatchQueue.global (sync) 之间的区别是什么?由于这个队列是并发的,每个队列应该在哪里使用? 第三个问题: 以下两种情况有什么区别?
- (串行和同步) - (并发和异步)
2个回答

11

据我理解:

队列不是线程

主队列和全局队列可以在同一个线程中工作

调度:将任务放入队列中

如果全局队列同步(sync)的方式在主队列上被调度,那么被调度的任务将在主队列的相同线程中运行,并且被添加到全局队列此任务将冻结线程。

如果全局队列异步(async)的方式在主队列上被调度,那么被调度的任务将在主队列的另一个线程中运行,并且被添加到全局队列此任务不会冻结线程。

如果主队列异步(async)的方式在主队列上被调度,那么被调度的任务将在主队列的相同线程中运行。

如果主队列同步(sync)的方式在主队列上被调度,会导致异常,因为会造成死锁(deadlock)

Dispatch.sync:将任务放入队列并等待其完成

Dispatch.async:将任务放入队列并不等待其完成(任务可能在同一个线程或另一个线程中运行)

  • 如果任务在全局队列上被调度,并且这符合主线程

  • 然后任务将被添加到全局队列中,新线程将被创建,任务将立即在新线程中开始工作。

  • 如果任务分发在主队列上,并且这符合主线程, 则任务将被添加到主队列中,直到较旧的任务完成工作后,它将不会立即执行(因为主队列是顺序执行的)。


3

DispatchQueue并不直接对应于单个线程。唯一的限制是只允许从主线程访问UI,这可以通过DispatchQueue.main实现。然而,如果您在特定队列上调用它,则系统不能保证将执行块分派到特定线程。

DispatchQueue.async是非阻塞操作,因此您可以在同一队列上异步执行多个代码块,而不会阻塞特定线程。这就是为什么您应该始终以异步方式将操作分派到主队列,以避免阻塞UI更新,因为主队列仅负责与UI相关的任务。在任何队列上调用async都不能保证执行将发生在特定线程(无论是后台还是主线程),它仅保证操作将以非阻塞方式执行。

DispatchQueue.sync是阻塞操作,这意味着在执行单个sync代码块时,特定的DispatchQueue上不能执行其他任何代码。因此,如果您将代码块同步分派到main队列,则会阻塞UI更新,从而导致应用程序冻结。


只要使用 DispatchQueue.global 时它是并发的,那么在使用 (sync) 时会被阻塞。并发 意味着队列中的每个元素都将在单独的线程中工作。 - Saeed Alasiry
@user3141421,并发“DispatchQueue”不存在。正如我所说,您可以同步地将执行块分派到队列(这将是阻塞操作)或异步地分派(非阻塞,这就是您可能称之为并发的方式),但队列本身不会是并发的。如果队列将工作项分派到几个不同的线程,则队列可以并发执行任务,但您可以通过同步地将执行块分派到它来阻止任何队列。 - Dávid Pásztor
1
根据苹果文档,我不同意你的看法:调度队列可以是串行的,这样工作项将按顺序执行,也可以是并发的。 - Saeed Alasiry
@user3141421 正确,但并发的 DispatchQueue 只是表示它具有并发执行任务的能力。这并不意味着它只能 __同时执行任务__。而同步地调度任务会使并发队列的行为类似于串行队列,直到同步阻塞操作完成执行。 - Dávid Pásztor
串行 DispatchQueue 是否只能同步工作? - Saeed Alasiry
@user3141421 不,你仍然可以将多个任务异步地分派到串行队列中,但是每次只会执行其中一个。但是,由于异步性,你无法预测分派的任务将以何种顺序执行。 - Dávid Pásztor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接