Swift-如何防止DispatchQueues在同一线程上执行?

时间:2019-02-18 20:19:02

标签: swift concurrency grand-central-dispatch deadlock dispatch-queue

我最近已经学习了很多有关线程和DispatchQueue的知识,并且遇到了一个大问题。我已经多次听到GCD不能保证给定工作块可以在哪个线程上执行。大多数时候,这是有用的级别抽象。但是,我遇到了一个我仍然不知道原因的错误,但是这使我意识到我认为这是GCD这方面的潜在陷阱。

示例:

let queue1 = DispatchQueue(label: "one")
let queue2 = DispatchQueue(label: "two")
queue1.sync {
    let importantValue1 = "importantValue1"
    let importantValue2 = queue2.sync {
        return "importantValue2"
    }
    print("did important work, got values", importantValue1, importantValue2)
}

我的问题是,至少可以保证我的队列不会在同一线程上执行吗?从我所看到的来看,似乎我没有这个保证。但是,没有它,我是否不会一直处于僵局的危险之中?在上面的示例中,如果两个队列都在线程7上执行,将会发生什么?调用queue2.sync会导致应用崩溃吗?

2 个答案:

答案 0 :(得分:0)

来自后台队列的任务永远不会阻止后台队列中的其他任务运行,因此,尽管您可能会遇到死锁,但是在同一线程上执行的队列不会导致死锁。

另一方面,在另一个队列上同步运行代码是毫无意义的。

答案 1 :(得分:0)

在大多数情况下,我会期望这两个块在同一队列上运行。实际上,让我们看看:

import Foundation

let queue1 = DispatchQueue(label: "one")
let queue2 = DispatchQueue(label: "two")
queue1.sync {
    let importantValue1 = "importantValue1"
    print(Thread.current)  // Print the current queue
    let importantValue2: String = queue2.sync {
        print(Thread.current) // Print the current queue
        return "importantValue2"
    }
    print("did important work, got values", importantValue1, importantValue2)
}

<NSThread: 0x6000023b2900>{number = 1, name = main}
<NSThread: 0x6000023b2900>{number = 1, name = main}
did important work, got values importantValue1 importantValue2

是的,在我的示例中,它们都在主线程上运行,就像您通常希望它们一样。在调用.sync时,通常没有理由强加切换线程的巨大成本。当前线程在该块完成之前无法执行任何操作,因此只要对该线程没有任何限制(例如,提交给主队列的块必须在主线程上运行。

您是正确的,如果您不小心,有可能生成死锁,但这不是因为使用了线程。死锁是循环使用.sync所固有的。无论使用什么底层线程,队列仍必须按一定顺序调度块,而这正是最常创建死锁的原因。