关于ios:DispatchQueue.main.async和DispatchQueue.main.sync之间的区别

Difference between DispatchQueue.main.async and DispatchQueue.main.sync

我已经使用DispatchQueue.main.async很长时间了,以执行与UI相关的操作。

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

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

1
2
3
4
5
6
7
8
9
10
DispatchQueue.main.async {
    self.imageView.image = imageView
    self.lbltitle.text =""

}

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

为什么要并发?

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

好。

我们需要注意一些抽象。

好。

  • 队列。
  • 同步/异步任务性能。
  • 优先事项。
  • 常见的麻烦。

  • 好。

    Queue列

    必须是串行或并发的。以及全球或私有。

    好。

    使用串行队列,任务将一个接一个地完成,而使用并发队列,任务将同时执行,并且将按意外的时间表完成。与并发队列相比,同一组任务将在串行队列上花费更多的时间。

    好。

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

    好。

    强烈建议不要在主队列上执行不涉及UI工作的繁重任务(例如,从网络中加载数据),而应在其他队列上执行这些任务以保持UI冻结并响应用户操作。如果我们允许在其他队列上更改UI,则可以按不同的意外时间表和速度进行更改。某些UI元素可以在需要之前或之后绘制。它可能会使UI崩溃。我们还需要记住,由于全局队列是系统队列,因此系统可以在它们上运行其他一些任务。

    好。

    服务质量/优先级

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

    还有

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

    好。

    任务可以同步或异步执行。

    好。

  • 同步功能仅在任务完成后才将控制权返回到当前队列。它阻止队列并等待直到任务完成。

    好。

  • 异步功能在发送任务以在其他队列上执行之后立即将控制权返回到当前队列。它不会等到任务完成。它不会阻塞队列。

    好。

  • 好。

    常见问题。

    程序员在开发并发应用程序时犯的最普遍的错误如下:

    好。

  • 竞争状态-在应用程序工作取决于代码部分执行的顺序时引起。
  • 优先级反转-当较高优先级的任务由于某些资源被阻塞而等待较小优先级的任务完成时
  • 死锁-当几个队列无限等待源(变量,数据等)已被其中一些队列阻塞时。
  • 好。

    切勿在主队列上调用同步功能。
    如果在主队列上调用sync函数,它将阻塞队列,队列将等待任务完成,但由于队列已中断,任务甚至无法启动,因此该任务将永远无法完成已经被封锁。这称为死锁。

    好。

    何时使用同步?
    当我们需要等到任务完成时。 F.e.当我们确保某些函数/方法没有被双重调用时。 F.e.我们进行了同步,并尝试防止重复调用它,直到完全完成为止。以下是针对此问题的一些代码:
    如何找出导致iOS设备上的错误崩溃报告的原因?

    好。

    好。


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

    何时使用sync?当您需要等待在不同队列上完成的事情然后才继续在当前队列上工作时

    使用同步的示例:

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


    GCD允许您执行任务synchronouslyasynchronously [关于] [更多]

    synchronous(阻止并等待)功能将在任务完成时返回控件

    asynchronous(调度并继续)功能立即返回控件,将任务分派以开始到适当的队列,但不等待其完成。


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

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

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


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     // Main Thread
     DispatchQueue.global(qos: .userInteractive).sync {
                self.tableView.reloadData()
       }

     //Thread 4 Queue : com.apple.root.user-interactive-qos (concurrent)
     DispatchQueue.global(qos: .userInteractive).async {
                // Can't do UI Stuff here
                self.tableView.reloadData()
       }

    Main Thread
    Thread 4 Queue : com.apple.root.user-interactive-qos (concurrent)

    • .userInteractive用于qos使您有两个关于线程的选择,
      您要么获得主线程,要么获得后台线程。这取决于您如何同步或异步执行线程。