为什么 DispatchGroup 会干扰主队列?

Why does DispatchGroup interfere with main queue?

我必须停止我的代码一秒钟,以便在继续之前同步服务器数据库。

下面的所有代码片段 运行 来自主线程。

我先用这个:

// code 1
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
    // dummy
}
// stuff

结果显然不尽如人意,因为东西是立即执行的。我想要 运行 在代码块之后延迟的东西(不好,但这是有原因的)。

// code 2
let group = DispatchGroup()
group.enter()
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
    group.leave()
}
group.wait()
// stuff

僵局!

问题 1:为什么主队列 without DispatchGroup 一起工作并锁定 with DispatchGroup?

// code 3
let group = DispatchGroup()
group.enter()
DispatchQueue.global().asyncAfter(deadline: .now() + 1.0) {
    group.leave()
}
group.wait()
// stuff

这符合预期!

问题 2:为什么 DispatchGroup 需要全局队列来延迟 运行?

我在这里读到这个:

我假设您 运行 在主线程上使用这些片段,因为从问题描述来看很可能就是这种情况。

调度队列基本上是任务队列,所以一个队列有一些任务入队。让我们看看在执行生成死锁的代码段时主队列上有什么。

  1. 主队列有一个任务正在执行(执行代码段的那个)
  2. 然后你调用 asyncAfter,它将在指定的截止日期后将另一个任务(包含 group.leave() 的闭包)排入主队列。

现在正在执行的任务 (1.) 被对 group.wait() 的调用阻塞,它将阻塞整个主队列,直到它完成执行。这意味着排队的任务 (2.) 将必须等到第一个完成。你可以在这里看到这两个任务会互相阻塞:

  • 第一个(1.)会等到第二个(2.)释放调度组
  • 第二个 (2.) 将等到第一个 (1.) 完成执行,以便可以安排

对于第 2 个问题,使用全局队列(或字面意义上的除我们当前代码正在执行的队列之外的任何其他队列 - 在本例中为主队列),不会阻塞 asyncAfter 任务(显然,因为它被调度到另一个未阻塞的队列上,因此它有机会被执行)。

串行调度队列也是如此(主队列也是串行队列)。串行调度队列将串行执行它们的任务,即一次只有一个。

另一方面,对于并发调度队列,这种情况不会导致死锁,因为asyncAfter任务不会被等待任务阻塞。这是因为并发调度队列不会等待正在执行的任务完成来调度下一个入队任务。

尝试在串行队列上 运行 这种情况,然后在并发队列上观察差异

甚至是一个很好的练习