ios - 为什么DispatchGroup会干扰主队列?

标签 ios swift grand-central-dispatch

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

下面的所有代码片段都从主线程运行。

我首先使用这个:

// 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:为什么主队列在没有 DispatchGroup 的情况下工作并与 DispatchGroup 一起锁定?

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

这按预期工作!

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

我在这里读到了这个:
https://stackoverflow.com/a/42773392/3657691/ https://stackoverflow.com/a/28821805/3657691/ https://stackoverflow.com/a/49287115/3657691/

最佳答案

我假设您正在主线程上运行这些代码片段,因为问题描述中很可能就是这种情况。

调度队列基本上是任务队列,因此队列中有一些任务排队。让我们看看当您执行产生死锁的代码片段时主队列上有什么。

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

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

  • 第一个 (1.) 将等待,直到第二个 (2.) 释放调度组
  • 第二个 (2.) 将等待第一个 (1.) 完成执行,以便进行调度

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

这对于串行调度队列来说是正确的(主队列也是串行队列)。串行调度队列将串行执行其任务,即一次仅执行一个任务。

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

这甚至是一个很好的练习,可以尝试在串行队列上运行此场景,然后在并发队列上运行以观察差异

关于ios - 为什么DispatchGroup会干扰主队列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68191691/

相关文章:

iOS 10 UIImagePickerController 黑屏

ios - 如何防止其他开发者破坏我们的 Parse 服务器数据

ios - 如何在 Swift 中创建自定义高阶函数,如 .maps() 或 .filter()

ios - 加载 UIImagePickerController 更快?

ios - 将 Swift 的调用同步到基于 C 的线程不安全库

multithreading - 我可以假设计划在串行队列上运行的 block 将全部在同一线程上运行吗?

ios - 如何让其他应用程序保存文件到我们的应用程序?

ios - 保持键盘在多个 View Controller 上可见并专注于每个文本字段

swift - 以编程方式获取 iCloud 文档共享链接

swift - 我如何在 Firestore 数据库中查询最近的、附近的 Geopoints?