Swift Async打印顺序?

时间:2018-10-10 05:23:26

标签: ios swift asynchronous grand-central-dispatch dispatch-async

这是否始终按1 5 2 4 3的顺序打印?

var x = 0.58m

我认为答案是否定的,但是我无法解释,希望有人可以澄清我的理解。谢谢!

2 个答案:

答案 0 :(得分:14)

这取决于您启动操作的线程。

如果您从主体开始,那么您将获得1, 5, 2, 4, 3

如果您是从后台线程开始的,那么大多数时候您会得到相同的结果(1, 5, 2, 4, 3),但这不能保证,因为后台线程可以在任何时候被置于休眠状态。操作系统,并且如果此操作恰好发生在print(5)调用之前,则最后打印出5。

请注意,如果问题中的代码是您的应用程序/操场中唯一的代码,那么您可能会因部分打印而感到惊讶,因为应用程序/操场一旦击中{{1} }行,然后才有机会执行异步调度。为了避免这种情况,您可以确保在主线程上执行print(5)作为代码的最后一部分。

下面是一些图,试图说明仅在主线程中发生的情况,以及其中涉及后台线程的情况:

enter image description here enter image description here

答案 1 :(得分:11)

您将始终得到1、2、4、3。5将始终位于1之后。但是,相对于其他结果,它的最终结局取决于整个事物开始的队列。

如果这是从主队列开始的,则5始终在1到2之间。

这是为什么:

此代码从主队列开始。打印1。然后,您将另一个块放入队列以在主队列上异步运行,以便该块将在当前块完成并且主队列到达当前运行循环的末尾之后运行。代码继续到要打印的下一行5。当前块结束,并且运行主队列中的下一个块。这是第一次调用DispatchQueue.main.async的块。在运行此块时,它会打印2(所以现在我们有1 5 2)。就像最后一个一样,另一个块也排队到主队列中。当前块继续并打印4(所以现在我们有1 5 2 4)。该块结束,并且运行主队列中的下一个块。这是我们添加的最后一个块。该块运行,并打印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