简体   繁体   English

提交到主“DispatchQueue”的项目是否会中断当前在主线程上执行的代码?

[英]Will an item submitted to the main `DispatchQueue` ever interrupt currently executing code on the main thread?

The below code is used to execute a long running calculation on a background thread:以下代码用于在后台线程上执行长时间运行的计算:

enum CalculationInterface {

    private static var latestKey: AnyObject?   // Used to cancel previous calculations when a new one is initiated.

    static func output(from input: Input, return: @escaping (Output?) -> ()) {
        self.latestKey = EmptyObject()
        let key = self.latestKey!   // Made to enable capturing `self.latestKey's` value.  

        DispatchQueue.global().async {
            do {
                let output = try calculateOutput(from: input, shouldContinue: { key === self.latestKey })   // Function cancels by throwing an error.
                DispatchQueue.main.async { if (key === self.latestKey) { `return`(output) } }
            } catch {}
        }
    }
} 

This function is called from the main thread like so:这个函数是从主线程调用的,如下所示:

/// Initiates calculation of the output and sets it to the result when finished.
private func recalculateOutput() {
    self.output = .calculating    // Triggers calculation in-progress animation for user.
    CalculationInterface.output(from: input) { self.output = $0 }   // Ends animation once set and displays calculated output to user.
}

I'm wondering if it's possible for the closure that's pushed to DispatchQueue.main to execute while the main thread is running my code.我想知道是否有可能在主线程运行我的代码时执行推送到DispatchQueue.main的闭包。 Or in other words execute after self.output = .calculating but before self.latestKey is re-set to the new object.或者换句话说,在self.output = .calculating但在self.latestKey重新设置为新对象之前执行。 If it could, then the stale calculation output could be displayed to the user.如果可以,则可以向用户显示陈旧的计算输出。

I'm wondering if it's possible for the closure that's pushed to DispatchQueue.main to execute while the main thread is running my code我想知道是否有可能在主线程运行我的代码时执行推送到DispatchQueue.main的闭包

No, it isn't possible.不,这是不可能的。 The main queue is a serial queue.主队列是串行队列。 If code is running on the main queue, no "other" main queue code can run.如果代码在主队列上运行,则不能运行“其他”主队列代码。 Your DispatchQueue.main.async effectively means: "Wait until all code running on the main queue comes naturally to an end, and then run this on the main queue."您的DispatchQueue.main.async实际上意味着:“等到在主队列上运行的所有代码自然结束,然后在主队列上运行它。”

On the other hand, DispatchQueue.global() is not a serial queue.另一方面, DispatchQueue.global()不是串行队列。 Thus it is theoretically possible for two calls to calculateOutput to overlap.因此,理论上有可能对calculateOutput两个调用重叠。 That isn't something you want to have happen;这不是你想要发生的事情; you want to be sure that any executing instance of calculateOutput finishes (and we proceed to grapple with the latestKey ) before another one can start.您希望确保任何正在执行的calculateOutput实例在另一个实例可以启动之前完成(并且我们继续处理latestKey )。 In other words, you want to ensure that the sequence换句话说,您要确保序列

  • set latestKey on the main thread在主线程上设置latestKey
  • perform calculateOutput in the background在后台执行calculateOutput
  • look at latestKey on the main thread查看主线程上的latestKey

happens coherently.连贯地发生。 The way to ensure that is to set aside a DispatchQueue that you create with DispatchQueue(label:) , that you will always use for running calculateOutput .确保这一点的方法是将您使用DispatchQueue(label:)创建的DispatchQueue(label:)放在一边,您将始终使用它来运行calculateOutput That queue will be a serial queue by default.默认情况下,该队列将是串行队列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM