Будет ли элемент, переданный в основное `DispatchQueue`, когда-либо прерывать выполнение кода в основном потоке? - PullRequest
0 голосов
/ 30 января 2020

Приведенный ниже код используется для выполнения длительного расчета в фоновом потоке:

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 {}
        }
    }
} 

Эта функция вызывается из основного потока следующим образом:

/// 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 ' Мне интересно, возможно ли выполнение замыкания, которое помещено в DispatchQueue.main, в то время как основной поток выполняет мой код. Или, другими словами, выполнить после self.output = .calculating, но перед self.latestKey будет установлен новый объект. Если это возможно, то устаревшие результаты вычислений могут отображаться для пользователя.

1 Ответ

3 голосов
/ 30 января 2020

Мне интересно, возможно ли выполнение замыкания, которое помещено в DispatchQueue.main, для выполнения, пока основной поток выполняет мой код

Нет, это невозможно. Основная очередь является последовательной очередью. Если код выполняется в основной очереди, никакой «другой» код основной очереди не может быть запущен. Ваш DispatchQueue.main.async фактически означает: «Подождите, пока весь код, выполняющийся в основной очереди, не завершится естественным образом, и , а затем запустите это в основной очереди».

С другой стороны, DispatchQueue.global() является , а не последовательной очередью. Таким образом, теоретически возможно, чтобы два вызова calculateOutput перекрывались. Это не то, что вы хотите, чтобы произошло; Вы хотите быть уверены, что любой выполняющийся экземпляр calculateOutput завершает работу (и мы приступаем к работе с latestKey), прежде чем может начаться другой. Другими словами, вы хотите убедиться, что последовательность

  • установить latestKey в основном потоке
  • выполнить calculateOutput в фоновом режиме
  • посмотреть на latestKey на основном потоке

происходит связно. Способ обеспечить это - отложить DispatchQueue, который вы создаете с помощью DispatchQueue(label:), который вы всегда будете использовать для запуска calculateOutput. По умолчанию эта очередь будет последовательной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...