【问题标题】:GCD serial async queue vs serial sync queue nested in asyncGCD串行异步队列与嵌套在异步中的串行同步队列
【发布时间】:2020-12-18 13:59:43
【问题描述】:

我必须保护我的代码的关键部分。 我不希望调用者被耗时的函数阻塞,所以我创建了一个带有后台 qos 的串行队列,然后异步调度:

private let someQueue = DispatchQueue(label: "\(type(of: self)).someQueue", qos: .background)

func doSomething() {
    self.someQueue.async { 
       //critical section
    }
}

据我了解,该函数将直接在调用线程上返回而不会阻塞。 我还看到某处首先在全局队列上异步调度,在串行队列上同步调度:

private let someQueue2 = DispatchQueue(label: "\(type(of: self)).someQueue2")

func doSomething() {
    DispatchQueue.global(qos: .background).async {
        self.someQueue2.sync { 
           //critical section
         }
    }
}

这两种方法有什么区别? 哪种方法是正确的?

【问题讨论】:

  • 第二种形式似乎是一个没有意识到本地调度队列可以并发的人的误解。
  • 你永远不应该在并发队列(全局队列是)中调用 dispatch_sync - 特别是当“关键部分”的执行时间可能很长时,因为这可能导致“线程爆炸”。 GCD 旨在让应用程序创建尽可能少的线程。所以,这实际上是一种“反模式”。所以,不同的是,方法 1 是可行的,方法 2 是错误的。
  • @CouchDeveloper 我同意你的观点,在遗留代码库中,我正在研究第一种方法在许多情况下都被使用,所以我质疑我的方法

标签: ios swift concurrency grand-central-dispatch


【解决方案1】:

在第一种方法中,调用线程不被阻塞,异步块中传递的任务(临界区)将在后台执行。

在第二种方法中,调用线程没有被阻塞,但“后台”线程将等待另一个线程执行的同步块(临界区)执行。

我不知道您在关键部分做了什么,但似乎第一种方法似乎是最好的方法。请注意,后台 qos 非常慢,除非您知道自己在做什么,否则可能为您的队列使用默认 qos。另请注意,约定希望您使用捆绑标识符作为队列的标签。所以是这样的:

private let someQueue = DispatchQueue(label: "\(Bundle.main.bundleIdentifier ?? "").\(type(of: self)).someQueue")

【讨论】:

  • 在我的关键部分中,我正在将日志写入附加内容的文件中。感谢您的解释和 qos 建议,您仍然建议不要使用背景吗?
  • 通常您应该使用的最低优先级是.utility。当设备处于低功耗状态时,后台优先级可能会不足。
猜你喜欢
  • 2021-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多