Я полагаю, вы неправильно прочитали этот комментарий в заголовке. Вопрос не в том, отправляете ли вы из очереди main
, а в том, отправляете ли вы в очередь main
.
Итак, вот хорошо известная sync
оптимизация, при которой отправленный блок будет выполняться в текущем потоке:
let backgroundQueue = DispatchQueue(label: "internalqueue", attributes: .concurrent)
// We'll dispatch from main thread _to_ background queue
func dispatchingToBackgroundQueue() {
backgroundQueue.sync {
print(#function, "this sync will run on the current thread, namely the main thread; isMainThread =", Thread.isMainThread)
}
backgroundQueue.async {
print(#function, "but this async will run on the background queue's thread; isMainThread =", Thread.isMainThread)
}
}
Когда вы используете sync
, вы говорите GCD: «Эй, пусть этот поток подождет, пока другой поток не выполнит этот блок кода». Итак, GCD достаточно умен, чтобы понять, «хорошо, если этот поток не будет ничего делать, пока я жду, пока будет запущен блок кода, я мог бы также запустить его здесь, если смогу, и сохранить дорогостоящий контекст». переключиться на другой поток. "
Но в следующем сценарии мы что-то делаем в некоторой фоновой очереди и хотим отправить ее обратно в очередь main
. В этом случае GCD не будет выполнять вышеупомянутую оптимизацию, а всегда будет запускать задачу, отправленную в очередь main
в очереди main
:
// but this time, we'll dispatch from background queue _to_ the main queue
func dispatchingToTheMainQueue() {
backgroundQueue.async {
DispatchQueue.main.sync {
print(#function, "even though it’s sync, this will still run on the main thread; isMainThread =", Thread.isMainThread)
}
DispatchQueue.main.async {
print(#function, "needless to say, this async will run on the main thread; isMainThread =", Thread.isMainThread)
}
}
}
Это происходит потому, что в основной очереди должны выполняться определенные вещи (например, обновления пользовательского интерфейса), и если вы отправляете его в основную очередь, он всегда выполнит этот запрос и не будет пытаться выполнить какие-либо действия. оптимизация, чтобы избежать переключения контекста.
Давайте рассмотрим более практический пример последнего сценария.
func performRequest(_ url: URL) {
URLSession.shared.dataTask(with: url) { data, _, _ in
DispatchQueue.main.sync {
// we're guaranteed that this actually will run on the main thread
// even though we used `sync`
}
}
}
Теперь, как правило, мы будем использовать async
при отправке обратно в основную очередь, но комментарий в документации заголовка sync
просто сообщает нам, что эта задача отправляется обратно в основную очередь с помощью sync
. фактически выполняется в основной очереди, а не в фоновой очереди URLSession
, как вы могли бы опасаться.