我已经使用DispatchQueue.main.async很长时间了,以执行与UI相关的操作。
Swift提供了DispatchQueue.main.async和DispatchQueue.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设备上的错误崩溃报告的原因?
好。
好。
-
嗨,亚历山大,请确认.userInteractive QoS是否在主线程上调度?因为我尝试在异步块中放置一个断点,并查看了Debug Navigator活动线程面板。从主线程调用DispatchQueue.global(qos:.userInteractive).async {}时,其显示的名称与主线程的名称不同
-
嗨,Nishu,是的,.userInteractive是用于主线程的QoS。它显示哪个名字?
-
我认为"永远不要在主队列上调用同步功能"是正确的。在某些情况下,您可能会在主线程中调用同步,例如,当您有一个全局计数器需要每个对象使用并增加以下值时:dispatchQueue.sync {count + = 1; self.orderId = count}
-
QOS类-.userInteractive不是主队列。
-
从后台线程调用DispatchQueue.main.sync是错误的吗?
-
@Honey,没什么错,但是根据我的经验,您会发现自己调用了DispatchQueue.main.async而不是sync。
-
根据我的理解,sync或async方法对调用它们的队列没有影响。 sync将阻止从中调用它的线程,而不是在其上调用队列。 DispatchQueue的属性决定了DispatchQueue是等待任务执行(串行队列)还是可以在当前任务完成之前运行下一个任务(并发队列)。因此,即使DispatchQueue.main.async是异步调用,如果main队列是一个串行队列,它也可以阻塞主线程(如果完成了一些繁重的工作)。
-
说您永远不要在当前队列上调用sync()函数会更准确吗?如果您正确理解,则在另一个队列中在主队列上调用sync()并没有错。
当您使用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返回带有更新的数据源之前删除另一张照片,从而导致致命的不一致错误。
-
@teacup不会在主线程上处理所有这些吗?主线程不是串行线程吗?因此一次。唯一会导致问题的原因完全是由于顺序或您在事情返回之前所说的。我的观点是您不会遇到并发问题。您会遇到赛车问题。那正确吗?
GCD允许您执行任务synchronously或asynchronously [关于] [更多]
synchronous(阻止并等待)功能将在任务完成时返回控件
asynchronous(调度并继续)功能立即返回控件,将任务分派以开始到适当的队列,但不等待其完成。
sync或async方法对调用它们的队列没有影响。
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()
} |

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