Swift - Как предотвратить выполнение DispatchQueues в том же потоке? - PullRequest
0 голосов
/ 18 февраля 2019

В последнее время я много узнал о многопоточности и DispatchQueues и пришел к большому вопросу.Я много раз слышал, что 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 голосов
/ 18 февраля 2019

В большинстве случаев я бы ожидал , что эти два блока будут работать в одной и той же очереди.На самом деле, давайте посмотрим:

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 по кругу.Независимо от того, какой базовый поток используется, очередь все равно должна отправлять блоки в определенном порядке, и именно это чаще всего создает тупики.

0 голосов
/ 18 февраля 2019

Задачи из фоновых очередей никогда не препятствуют выполнению других задач из фоновых очередей, поэтому, хотя вы можете получить взаимоблокировки, очереди, выполняющиеся в том же потоке, не вызовут его.

С другой стороны, синхронный запуск вашего кода в другой очереди довольно бессмысленен.

...