Swift异步打印命令?

Uni*_*orn 15 asynchronous grand-central-dispatch ios dispatch-async swift

这总是以1 5 2 4 3的顺序打印吗?

print("1")
DispatchQueue.main.async {
    print("2")
    DispatchQueue.main.async {
        print(3)
    }
    print("4")
}
print("5")
Run Code Online (Sandbox Code Playgroud)

我觉得答案是否定的,但我无法解释,希望有人能澄清我的理解.谢谢!

Cri*_*tik 14

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

如果你从主要开始,那么你得到 1, 5, 2, 4, 3

如果你从后台线程开始,那么大多数时候你会得到相同的result(1, 5, 2, 4, 3),但是这不能保证,因为操作系统可以随时让后台线程进入休眠状态,如果这种情况发生在之前的print(5)呼叫,则5将是最后被打印.

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

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

在此输入图像描述 在此输入图像描述


rma*_*ddy 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()
}
Run Code Online (Sandbox Code Playgroud)

循环的存在导致5在它出现之前花费更长的时间,这允许主队列在打印5之前执行一些.没有循环,后台线程执行得太快,所以5出现在2之前.

如果在游乐场中运行此测试,请添加:

PlaygroundPage.current.needsIndefiniteExecution = true
Run Code Online (Sandbox Code Playgroud)

到了操场的顶部(就在进口之后).您还需要:

import PlaygroundSupport
Run Code Online (Sandbox Code Playgroud)