ios - 从多个 BackgroundThreads 到 MainThread 的调用可以同时发生吗?
问题描述
可能有很多更好的方法可以用完全不同的方法解决这个问题,但请幽默。我想知道这个确切的情况。
这里我有两个函数,doSomething
和doSomethingElse
. 它们被调用 from doEverything()
,并且都返回一个将触发异步的 completionBlock。
目标是在everythingDone()
这两个异步调用完成后立即调用。正如我所说,可能有更好的方法来解决这个问题,但我想知道这个确切的逻辑会发生什么。
在两个完成中,我检查两个完成是否都已完成,everythingDone
如果是则调用。
func doSomething(completion:((Int)->())?){
DispatchQueue.global(qos: .background).async {
completion?(123)
}
}
func doSomethingElse(completion:((String)->())?){
DispatchQueue.global(qos: .background).async {
completion?("Test")
}
}
func doEverything(){
var values:[Any] = []
var somethingDone:Bool = false
var somethingElseDone:Bool = false
doSomething { (value) in
DispatchQueue.main.async {
values.append(value)
somethingDone = true
if somethingDone && somethingElseDone{
self.everythingDone(values: values)
}
}
}
doSomethingElse { (value) in
DispatchQueue.main.async {
values.append(value)
somethingElseDone = true
if somethingDone && somethingElseDone{
self.everythingDone(values: values)
}
}
}
}
func everythingDone(values:[Any]){
print("Everything done: ", values)
}
可以everythingDone
发生两次吗?事件的顺序是否有可能导致这种情况:
- DoSomething-完成集
somethingDone=true
- DoSomethingElse-完成集
somethingElseDone = true
- DoSomething-completion 检查两者是否为真,它们是
- DoSomethingElse-completion 检查两者是否为真,它们是。
这会发生吗?main.asyc 调用可以“交织”发生吗?
解决方案
简短的回答:
不。everythingDone
不能调用两次 。
长答案:
主队列(DispatchQueue.main
)是一个串行队列,这意味着任务将一个接一个完成,第二个DispatchQueue.main.async
闭包将等到第一个完成它的工作。
一个小示范:
想象一下下面的代码:
DispatchQueue.global(qos: .background).async {
DispatchQueue.main.async {
//Closure A
for i in 0..<10 {
print("a\(i)")
}
}
}
DispatchQueue.global(qos: .background).async {
DispatchQueue.main.async {
//Closure B
for i in 0..<10 {
print("b\(i)")
}
}
}
如果您运行此代码,您将在控制台中看到以下结果:
a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 b0 b1 b2 b3 b4 b5 b6 b7 b8 b9
如您所见,首先它运行并完成里面的代码Close A
,并且只有在它开始并完成里面的代码之后Closure B
。
但是,如果我们稍微修改一下代码(通过将闭包直接移动到全局队列:
DispatchQueue.global(qos: .background).async {
//Closure A
for i in 0..<10 {
print("a\(i)")
}
}
DispatchQueue.global(qos: .background).async {
//Closure B
for i in 0..<10 {
print("b\(i)")
}
}
结果如下:
b0 a0 b1 b2 b3 b4 b5 a1 b6 a2 b7 a3 b8 a4 a5 a6 a7 a8 a9 b9
在这里你可以看到顺序是被破坏的,甚至是不可预测的,每次执行都可能发生变化。这是因为DispatchQueue.global(qos: .background)
是并发队列,所以任务将同时执行,并且会在意想不到的时间表上完成。
因此,一旦您的闭包在串行队列中(在您的情况下是主队列),那么答案是NO,否则,答案是YES。
推荐阅读
- python-3.x - 如何在管道中使用适当的 FunctionTransformer 制作 GridSearchCV?
- html - 不同行的李标签
- groovy - 是否可以为此 Query.builder() 参数添加空检查?
- mysql - 如何将 JSON 存储在 MySQL 数据库表字段中?
- javascript - 在 Array(3) 与 [1,2,3] 之间映射一个常量函数:为什么它们不同
- php - 通过测试中的方法传递请求
- html - 有没有办法让这个按钮动画?
- sftp - 使用 Pentaho 从远程 SFTP 删除超过 7 天的文件
- cakephp - CakePHP在最后一页输出多余的分页链接
- javascript - 我如何获取类似于数据库中字段的值?