![](/img/trans.png)
[英]DispatchQueue.main.async doesn't crash but DispatchQueue.main.sync crashes?
[英]Difference between DispatchQueue.main.async and DispatchQueue.main.sync
我一直在使用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 = ""
}
一旦您向应用程序添加繁重的任务(例如数据加载),它就会减慢您的 UI 工作速度,甚至冻结它。 并发使您可以“同时”执行 2 个或更多任务。 这种方法的缺点是线程安全性并不总是那么容易控制。 Fe 当不同的任务想要访问相同的资源时,例如尝试更改不同线程上的相同变量或访问已被不同线程阻塞的资源。
我们需要注意一些抽象。
必须是串行的或并发的。 以及同时全局或私有。
在串行队列中,任务将一个一个地完成,而在并发队列中,任务将同时执行并按意外的时间表完成。 与并发队列相比,同一组任务在串行队列上花费的时间更多。
您可以创建自己的专用队列(串行或并发)或使用已经可用的全局(系统)队列。 主队列是所有全局队列中唯一的串行队列。
强烈建议不要在主队列上执行与 UI 工作无关的繁重任务(从网络加载数据),而是在其他队列上执行这些任务,以保持 UI 不冻结并响应用户操作。 如果我们让其他队列上的 UI 更改,则可以以不同且意外的时间表和速度进行更改。 一些 UI 元素可以在需要之前或之后绘制。 它可能会导致用户界面崩溃。 我们还需要记住,由于全局队列是系统队列,因此系统可以在它们上运行一些其他任务。
队列也有不同的qos(服务质量) ,它设置任务执行优先级(从高到低):
.userInteractive -主队列
.userInitiated - 用于用户启动的任务,用户等待某些响应
.utility - 用于需要一些时间且不需要立即响应的任务,例如处理数据
.background - 用于与视觉部分无关且对完成时间不严格的任务)。
还有
.default队列,不传输qos信息。 如果无法检测到qos ,则将在.userInitiated和.utility之间使用qos 。
任务可以同步或异步执行。
同步函数只有在任务完成后才将控制权返回到当前队列。 它阻塞队列并等待任务完成。
异步函数在发送任务后立即将控制权返回到当前队列以在不同队列上执行。 它不会等到任务完成。 它不会阻塞队列。
程序员在预测并发应用程序时最常犯的错误如下:
永远不要在主队列上调用同步函数。
如果您在主队列上调用同步函数,它将阻塞队列,队列将等待任务完成但任务永远不会完成,因为它甚至无法启动,因为队列是已经屏蔽了。 它被称为死锁。
什么时候使用同步? 当我们需要等到任务完成时。 Fe,当我们确保某些函数/方法不被重复调用时。 Fe 我们有同步并试图防止它被双重调用,直到它完全完成。 这是针对此问题的一些代码:
如何找出是什么导致了 IOS 设备上的错误崩溃报告?
当您使用async
它可以让调用队列继续移动,而无需等到执行分派的块。 相反, sync
将使调用队列停止并等待您在块中分派的工作完成。 因此sync
容易导致死锁。 尝试从主队列运行DispatchQueue.main.sync
并且应用程序将冻结,因为调用队列将等到调度块结束但它甚至无法启动(因为队列已停止并等待)
什么时候使用sync
? 当您需要等待在 DIFFERENT 队列上完成某事,然后才继续处理当前队列时
使用同步的示例:
在串行队列上,您可以将sync
用作互斥锁,以确保只有一个线程能够同时执行受保护的代码段。
sync
或async
方法对调用它们的队列没有影响。
sync
将阻止从其中它被称为并且它们不是在它被称为队列中的线程。 DispatchQueue
的属性决定了DispatchQueue
等待任务执行(串行队列)还是可以在当前任务完成之前运行下一个任务(并发队列)。
因此,即使DispatchQueue.main.async
是异步调用,添加到其中的重型操作也会冻结 UI,因为其操作是在主线程上串行执行的。 如果从后台线程调用此方法,即使 UI 似乎被冻结,控制权也会立即返回该线程。 这是因为async
调用是在DispatchQueue.main
// 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()
}
.userInteractive
可以使您对线程有两个选择,要么获取主线程,要么获取后台线程。 这取决于您将如何同步或异步执行线程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.