【问题标题】:Difference between DispatchQueue.main.async and DispatchQueue.main.syncDispatchQueue.main.async 和 DispatchQueue.main.sync 之间的区别
【发布时间】:2017-11-03 14:37:22
【问题描述】:

我长期使用DispatchQueue.main.async进行UI相关的操作。

Swift 提供了DispatchQueue.main.asyncDispatchQueue.main.sync,两者都在主队列上执行。

谁能告诉我它们之间的区别?我应该什么时候使用每个?

DispatchQueue.main.async {
    self.imageView.image = imageView
    self.lbltitle.text = ""

}

DispatchQueue.main.sync {
    self.imageView.image = imageView
    self.lbltitle.text = ""
}

【问题讨论】:

    标签: ios swift multithreading swift3 concurrency


    【解决方案1】:

    为什么要并发?

    一旦您向应用程序添加繁重的任务(例如数据加载),它就会减慢您的 UI 工作甚至冻结它。 并发允许您“同时”执行 2 个或更多任务。 这种方法的缺点是线程安全并不总是那么容易控制。 F.e.当不同的任务想要访问相同的资源时,例如尝试更改不同线程上的相同变量或访问已被不同线程阻塞的资源。

    我们需要注意一些抽象。

    • 队列。
    • 同步/异步任务性能。
    • 优先级。
    • 常见问题。

    队列

    必须是串行并发。以及 globalprivate 同时。

    对于串行队列,任务将一个接一个地完成,而对于并发队列,任务将同时执行,并且会在意想不到的计划中完成。与并发队列相比,同一组任务在串行队列上会花费更多时间。

    您可以创建自己的私有队列串行并发)或使用已经可用的全局(系统)队列。 主队列是所有全局队列中唯一的串行队列

    强烈建议不要在 主队列 上执行与 UI 工作无关的繁重任务(从网络加载数据),而是在其他队列上执行以保持UI 解冻并响应用户操作。如果我们让其他队列上的 UI 发生变化,则可以按照不同的、意想不到的时间表和速度进行更改。一些 UI 元素可以在需要之前或之后绘制。它可能会使 UI 崩溃。我们还需要记住,由于全局队列系统队列,系统可以在它们上面运行一些其他任务。

    服务质量/优先级

    队列也有不同的qos(服务质量),它设置任务执行的优先级(这里从最高到最低):
    .userInteractive - 主队列
    .userInitiated - 用于用户等待响应的用户启动任务
    .utility - 对于需要一些时间且不需要立即响应的任务,例如使用数据
    .background - 对于与视觉部分无关且不相关的任务完成时间严格)。

    还有一个

    .default 队列不传输 qos 信息。 如果无法检测到 qos,则将在 .userInitiated.utility 之间使用 qos

    任务可以同步异步执行。

    • 同步函数仅在任务完成后将控制权返回给当前队列。它阻塞队列并等待任务完成。

    • 异步 函数在发送任务以在不同队列上执行后立即将控制权返回给当前队列。它不会等到任务完成。它不会阻塞队列。

    常见问题。

    程序员在投影并发应用程序时最常犯的错误如下:

    • 竞争条件 - 当应用工作取决于代码部分执行的顺序时导致。
    • 优先级倒置 - 当较高优先级的任务由于某些资源被阻塞而等待较小优先级的任务完成时
    • 死锁 - 当一些队列无限等待已经被其中一些队列阻塞的源(变量、数据等)时。

    切勿在主队列中调用同步函数
    如果您在主队列上调用同步函数,它将阻塞队列,并且队列将等待任务完成但任务永远不会完成,因为它甚至无法启动,因为队列是已经被屏蔽了。它被称为死锁

    何时使用同步? 当我们需要等到任务完成时。 F.e.当我们确保某些函数/方法没有被双重调用时。 F.e.我们有同步并试图防止它被双重调用,直到它完全完成。以下是解决此问题的一些代码:
    How to find out what caused error crash report on IOS device?

    【讨论】:

    • 我认为“永远不要在主队列上调用同步函数”是不对的。在某些情况下,您会在主线程中调用同步,例如当您有一个需要每个对象使用并增加的全局计数器时:dispatchQueue.sync { count += 1; self.orderId = count }
    • QOS 类 - .userInteractive 不是主队列。
    • 从后台线程调用DispatchQueue.main.sync会不会出错?
    • @Honey,不,这样称呼并没有错,但根据我的经验,您会发现自己调用 DispatchQueue.main.async 而不是同步。
    • 不应该更准确地说你不应该在当前队列上调用 sync() 函数吗?如果我理解正确的话,如果你在另一个队列中,在主队列上调用 sync() 并没有错。
    【解决方案2】:

    当您使用async 时,它让调用队列继续前进,而无需等待调度的块被执行。相反,sync 将使调用队列停止并等待,直到您在块中调度的工作完成。因此sync 容易导致死锁。尝试从主队列运行DispatchQueue.main.sync,应用程序将冻结,因为调用队列将等待调度块结束,但它甚至无法启动(因为队列已停止并等待)

    什么时候使用sync?当您需要等待在不同队列上完成某些事情,然后才继续在当前队列上工作时

    使用同步的例子:

    在串行队列上,您可以使用sync 作为互斥体,以确保只有一个线程能够同时执行受保护的代码段。

    【讨论】:

    • 从后台线程调用DispatchQueue.main.sync会不会出错?
    • @Honey 一般来说,这样的调用没有任何问题(只要主队列不做任何繁重且耗时的事情),但实际上我想不出这样的情况你真的需要这个。肯定有更好的解决方案
    • @Honey 一种这样的情况是从 PhotoKit API 更新 PHAssets 的 CollectionView,如下面的文档所示:developer.apple.com/documentation/photokit/…
    • @teacup 很有趣。我只是想知道如果我们在那里调用async 会有什么不同?我的意思是,因为之后线程上没有其他内容,所以它没有任何区别。如果它是DispatchQueue.main.sync {block1}; DispatchQueue.main.sync {block2};,那将是有道理的。但是当没有其他块时,我想不出使用DispatchQueue.main.sync {Oneblock} 而不是DispatchQueue.main.async {Oneblock} 的好处。对于他们俩来说,他们将获得 mainQueue 优先级/即时性,并且没有任何事情会打断他们。
    • @Honey “因为线程上没有其他东西”当您在主线程上时是不正确的,主线程负责处理与应用程序的所有用户交互。因此,例如,用户可能会在 photoLibraryDidChange 返回更新的数据源之前删除另一张照片,从而导致致命的不一致错误。
    【解决方案3】:

    syncasync 方法对调用它们的队列没有影响。

    sync 将阻塞 from 它被调用的线程,而不是它被调用的队列 onDispatchQueue 的属性决定了DispatchQueue 是等待任务执行(串行队列)还是可以在当前任务完成之前运行下一个任务(并发队列)。

    因此,即使DispatchQueue.main.async 是异步调用,添加到其中的繁重操作也会冻结 UI,因为它的操作是在主线程上串行执行的。如果从后台线程调用此方法,即使 UI 似乎被冻结,控制也会立即返回该线程。这是因为async 调用是在DispatchQueue.main 上进行的

    【讨论】:

    • 我猜你错了,syncasync 指的是 Queue 作为 Queue 类型的方法,而不是 Thread 当你说 myDispatchQueue.sync {队列被阻塞,控制将停止,直到提交的工作完成,而不是线程,因为你不知道当你向队列提交工作时你会得到哪个线程,这就是为什么如果你调用@987654334 @形成主队列,你的代码将被冻结,因为主队列在主队列完成之前不会移动,所以我等到自己工作,但我不能工作,因为我在等待,死锁!跨度>
    【解决方案4】:

    GCD 允许您执行任务synchronouslyasynchronously[About]

    synchronous(block and wait) 函数返回一个控制任务何时完成

    asynchronous(dispatch and continue) 函数立即返回一个控件,将任务分派到适当的队列开始,但不等待它完成。

    [DispatchQueue]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-11
      • 2018-12-01
      • 1970-01-01
      • 2021-12-25
      • 2020-05-10
      • 2014-09-20
      • 2010-10-28
      • 2015-10-04
      相关资源
      最近更新 更多