DispatchQueue.main.async和DispatchQueue.main.sync

时间:2017-06-02 08:48:05

标签: ios swift multithreading swift3 concurrency

我一直在使用DispatchQueue.main.async很长一段时间来执行一些与UI相关的操作。 但Swift提供了DispatchQueue.main.async和DispatchQueue.main.sync,两者都在主队列中执行。 那么有谁可以告诉我他们之间的区别? 我什么时候应该使用它们? 提前谢谢。

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

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

        }

5 个答案:

答案 0 :(得分:115)

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

我们需要注意一些抽象。

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

<强>队列即可。

必须序列并发。与全球私人同时使用。

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

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

强烈建议不要执行在主队列上没有引用UI工作的繁重任务(从网络加载数据),而是在其他队列上执行这些任务以保持用户界面解冻并响应用户操作。如果我们在其他队列上更改UI,则可以根据不同的意外计划和速度进行更改。可以在需要之前或之后绘制一些UI元素。它可能会导致UI崩溃。我们还需要记住,由于全局队列系统队列,因此系统可以在其上运行一些其他任务。


服务质量/优先级

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

还有一个不会转移的 .default 队列 qos 信息。 如果无法检测 qos .userInitiated .utility 之间将使用 qos

任务可以同步异步执行。

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

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

常见问题。

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

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

永远不要调用主队列上的同步功能 如果你在主队列上调用sync函数,它将阻塞队列,并且队列将等待任务完成但是任务永远不会完成,因为它甚至无法启动,因为队列是已被封锁。它被称为死锁

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

答案 1 :(得分:20)

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

何时使用sync?当您需要等待在不同队列上完成的任务时,然后才继续处理当前队列

使用同步的示例:

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

答案 2 :(得分:0)

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

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

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

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:-1)

 // 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使您对线程有两种选择,  您要么获得主线程,要么获得后台线程。这取决于您如何同步或异步执行线程。