【问题标题】:Why we use async on main thread为什么我们在主线程上使用异步
【发布时间】:2019-04-09 07:09:43
【问题描述】:

在主线程以外的线程上更新 UI 是一个常见错误,可能会导致错过 UI 更新、视觉缺陷、数据损坏和崩溃。

https://developer.apple.com/documentation/code_diagnostics/main_thread_checker

例子:

let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
   if let data = data {
      DispatchQueue.main.async { // Correct
         self.label.text = "\(data.count) bytes downloaded"
      }
   }
}
task.resume()

我的问题从这里开始—— 当我们说.async 表示与.main 不同时(或不平行)时,我对上述陈述感到困惑。有人可以解释我的问题吗?

【问题讨论】:

  • DispatchQueue.main.async 表示您在主队列中排队一个任务,而无需等待任务执行。主队列任务将自动在主线程上运行,由操作系统调度。
  • 将每个DispatchQueue 视为工人。调用.async会在worker的TODO列表下添加一个任务,不要等待worker完成任务。 DispathQueue.main 是在主线程上工作的特定工作者。
  • .sync 将阻塞线程,直到任务块完成执行。您可以在主线程以外的任何线程上调用.sync,因为不能阻塞主线程。这并不意味着您不能致电DispatchQueue.main.sync。您可以像在非主线程上调用任何自定义 dispathQueue.sync 一样调用 DispatchQueue.main.sync。例如DispatchQueue(label: "bgqueue", qos: .background).async{ DispatchQueue.main.sync{} } 没问题。但DispatchQueue.main.asycn{ DispatchQueue.main.sync{} } 不是。
  • .sync 通常不是很有用。如果您希望在主队列任务之后发生某些事情,您只需将“某事”也排队到主队列中。如果没有必要,不值得阻塞线程。
  • 是的。在这种情况下,从bgqueuemain 发出一个任务,然后bgqueue 被阻塞以等待main 上的任务完成。

标签: ios swift grand-central-dispatch


【解决方案1】:

DispatchQueue.main.async 表示您在主队列中排队一个任务,而无需等待任务执行。主队列任务将自动在主线程上运行,由操作系统调度。

将每个DispatchQueue 视为工人。调用.async会在worker的TODO列表下添加一个任务,不要等待worker完成任务。 DispathQueue.main 是在主线程上工作的特定工作者。

另一方面,.sync 将阻塞线程,直到任务块完成执行。您可以在主线程以外的任何线程上调用.sync,因为不能阻塞主线程。

这并不意味着您不能致电DispatchQueue.main.sync。您可以像在非主线程上调用任何自定义 dispathQueue.sync 一样调用 DispatchQueue.main.sync。

例如

DispatchQueue(label: "bgqueue", qos: .background).async
{ 
    DispatchQueue.main.sync{} 
} 

没问题。

但是

DispatchQueue.main.async{ 
    DispatchQueue.main.sync{} 
} 

不是。

.sync 通常不是很有用。如果您希望在主队列任务之后发生某些事情,您只需将“某事”也排队到主队列中。如果没有必要,不值得阻塞线程。

话虽如此,使用.sync 时要记住两条规则,无论哪个队列正在接收.sync 调用:

  1. 永远不要从队列中调用.sync,这会导致死锁。
  2. 永远不要从主队列调用.sync,这会阻塞 UI 线程。

【讨论】:

    【解决方案2】:

    我认为您对 DispatchQueue 的工作方式感到困惑。

    DispatchQueue 只是管理线程池,当我们给它一个代码块来执行它时,它只需选择一个空闲线程并在其上运行那段代码。

    所以基本上一个线程可以被多个队列使用。队列只是一个任务列表,它管理着将来要执行的所有任务。

    所以基本上在这里,当您执行 DispatchQueue.main.async 时,您只是在指示 main queue 执行您的代码,而无需等待待处理的任务执行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-06
      • 1970-01-01
      • 2019-03-27
      • 2013-12-06
      • 2015-08-16
      • 2019-05-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多