Swift 异步打印命令?
Swift Async print order?
这是否总是按 1 5 2 4 3 的顺序打印?
print("1")
DispatchQueue.main.async {
print("2")
DispatchQueue.main.async {
print(3)
}
print("4")
}
print("5")
我觉得答案是否定的,但我无法解释,希望有人能澄清我的理解。谢谢!
你总是会得到 1、2、4、3。5 总是在 1 之后。但是它相对于其他队列的结束位置取决于整个队列是从哪个队列开始的。
如果这是从主队列开始的,那么 5 将始终在 1 和 2 之间。
原因如下:
此代码从主队列开始。 1 被打印出来。然后,您在主队列上异步地将另一个块排队到 运行,以便在当前块完成并且主队列到达当前 运行 循环的末尾后,该块将是 运行。代码继续到下一行,即打印 5。当前块结束,主队列中的下一个块是 运行。这是第一次调用 DispatchQueue.main.async
的块。由于此块 运行s 它打印 2(所以现在我们有 1 5 2)。另一个块与上一个块一样排入主队列。当前块继续并打印 4(所以现在我们有 1 5 2 4)。该块结束,主队列中的下一个块是 运行。这是我们添加的最后一个块。该块 运行s 并打印 3 给出最终输出 1 5 2 4 3.
如果您从某个后台队列开始,那么 5 可以出现在 1 之后的任何位置,但对于这样简单的代码,5 很可能仍会出现在 1 和 2 之间,但在一般情况下它可以出现在 1 之后的任何位置。
原因如下:
此代码在后台队列上启动。 1 被打印出来。然后,您在主队列上异步地将另一个块排队到 运行,以便在当前主队列 运行 循环完成后,该块将成为 运行。代码继续到下一行,即打印 5。当前块结束。添加到主队列的块与后台队列并行运行。根据添加到主队列的块是 运行 相对于后台队列中剩余代码是 运行 的时间,print("5")
的输出可以与打印混合来自主队列。这就是为什么从后台启动时 5 可以出现在 1 之后的任何位置。
但是问题中的简单代码即使在后台启动时也可能总是给出 1 5 2 4 3,因为代码很短,花费的时间也很少。
下面是一些将 5 放在别处的代码:
func asyncTest() {
print("1")
DispatchQueue.main.async {
print("2")
DispatchQueue.main.async {
print(3)
}
print("4")
}
for _ in 0...1000 {
}
print("5")
}
DispatchQueue.global(qos: .background).async {
asyncTest()
}
循环的存在导致 5 在它出现之前花费了更长的时间,这允许主队列在 5 被打印之前执行一些。没有循环,后台线程执行得太快,所以 5 出现在 2 之前。
如果运行在操场上进行此测试,请添加:
PlaygroundPage.current.needsIndefiniteExecution = true
到游乐场的顶部(就在进口之后)。您还需要:
import PlaygroundSupport
要看你是从哪个线程开始操作的
如果你从 main 开始,那么你会得到 1, 5, 2, 4, 3
如果您从后台线程开始,那么大多数情况下您会得到相同的结果 (1, 5, 2, 4, 3
),但是这并不能保证,因为后台线程可以随时进入休眠状态通过 OS,如果这发生在 print(5)
调用之前,那么 5 将是最后打印的。
请注意,如果问题中的代码是您 app/playground 中唯一的代码,那么您可能会对 运行 变成部分打印感到惊讶,因为 app/playground 退出一旦它到达 print(5)
行,在有机会执行异步调度之前。为了避免这种情况,您可以确保 RunLoop.current.run()
作为代码的最后一部分在主线程上执行。
这里有一些图表试图说明在仅主线程场景中发生的情况,以及涉及后台线程的场景:
这是否总是按 1 5 2 4 3 的顺序打印?
print("1")
DispatchQueue.main.async {
print("2")
DispatchQueue.main.async {
print(3)
}
print("4")
}
print("5")
我觉得答案是否定的,但我无法解释,希望有人能澄清我的理解。谢谢!
你总是会得到 1、2、4、3。5 总是在 1 之后。但是它相对于其他队列的结束位置取决于整个队列是从哪个队列开始的。
如果这是从主队列开始的,那么 5 将始终在 1 和 2 之间。
原因如下:
此代码从主队列开始。 1 被打印出来。然后,您在主队列上异步地将另一个块排队到 运行,以便在当前块完成并且主队列到达当前 运行 循环的末尾后,该块将是 运行。代码继续到下一行,即打印 5。当前块结束,主队列中的下一个块是 运行。这是第一次调用 DispatchQueue.main.async
的块。由于此块 运行s 它打印 2(所以现在我们有 1 5 2)。另一个块与上一个块一样排入主队列。当前块继续并打印 4(所以现在我们有 1 5 2 4)。该块结束,主队列中的下一个块是 运行。这是我们添加的最后一个块。该块 运行s 并打印 3 给出最终输出 1 5 2 4 3.
如果您从某个后台队列开始,那么 5 可以出现在 1 之后的任何位置,但对于这样简单的代码,5 很可能仍会出现在 1 和 2 之间,但在一般情况下它可以出现在 1 之后的任何位置。
原因如下:
此代码在后台队列上启动。 1 被打印出来。然后,您在主队列上异步地将另一个块排队到 运行,以便在当前主队列 运行 循环完成后,该块将成为 运行。代码继续到下一行,即打印 5。当前块结束。添加到主队列的块与后台队列并行运行。根据添加到主队列的块是 运行 相对于后台队列中剩余代码是 运行 的时间,print("5")
的输出可以与打印混合来自主队列。这就是为什么从后台启动时 5 可以出现在 1 之后的任何位置。
但是问题中的简单代码即使在后台启动时也可能总是给出 1 5 2 4 3,因为代码很短,花费的时间也很少。
下面是一些将 5 放在别处的代码:
func asyncTest() {
print("1")
DispatchQueue.main.async {
print("2")
DispatchQueue.main.async {
print(3)
}
print("4")
}
for _ in 0...1000 {
}
print("5")
}
DispatchQueue.global(qos: .background).async {
asyncTest()
}
循环的存在导致 5 在它出现之前花费了更长的时间,这允许主队列在 5 被打印之前执行一些。没有循环,后台线程执行得太快,所以 5 出现在 2 之前。
如果运行在操场上进行此测试,请添加:
PlaygroundPage.current.needsIndefiniteExecution = true
到游乐场的顶部(就在进口之后)。您还需要:
import PlaygroundSupport
要看你是从哪个线程开始操作的
如果你从 main 开始,那么你会得到 1, 5, 2, 4, 3
如果您从后台线程开始,那么大多数情况下您会得到相同的结果 (1, 5, 2, 4, 3
),但是这并不能保证,因为后台线程可以随时进入休眠状态通过 OS,如果这发生在 print(5)
调用之前,那么 5 将是最后打印的。
请注意,如果问题中的代码是您 app/playground 中唯一的代码,那么您可能会对 运行 变成部分打印感到惊讶,因为 app/playground 退出一旦它到达 print(5)
行,在有机会执行异步调度之前。为了避免这种情况,您可以确保 RunLoop.current.run()
作为代码的最后一部分在主线程上执行。
这里有一些图表试图说明在仅主线程场景中发生的情况,以及涉及后台线程的场景: