Какие типы очередей бывают в GCD и в чем их отличия
Что проверяют
Понимаете ли вы, чем очередь отличается от потока, и не путаете ли последовательность выполнения с синхронностью вызова. Это база многопоточности в iOS, на ней потом строятся вопросы про гонки и зависания интерфейса.
Как отвечать
Очередь в GCD принимает задачи и раздаёт их пулу потоков. Типов немного:
- последовательная (serial): задачи выполняются строго одна за другой, следующая ждёт предыдущую. Удобно как замена блокировке: доступ к общему состоянию через свою последовательную очередь снимает гонки;
- параллельная (concurrent): задачи стартуют одновременно, порядок завершения не гарантирован. Подходит для независимой работы вроде загрузки картинок;
- главная (main): последовательная очередь главного потока. Любое обновление интерфейса только здесь;
- глобальные (global): готовые параллельные очереди с приоритетом через QoS:
.userInteractive,.userInitiated,.utility,.background; - собственные: создаются через
DispatchQueue(label:attributes:), по умолчанию последовательные, с.concurrentпараллельные.
Отдельно проговорите вторую ось, которая и путается: sync и async это про то, ждёт ли вызывающий поток, а serial и concurrent про то, как выполняются задачи внутри очереди. Эти свойства независимы.
let queue = DispatchQueue(label: "com.app.cache") // serial
queue.async { cache[key] = value } // запись без гонок
DispatchQueue.global(qos: .utility).async {
let image = downloadImage()
DispatchQueue.main.async { imageView.image = image }
}Где спотыкаются
Вызывают DispatchQueue.main.sync из главного потока и получают мгновенный дедлок.
Считают, что параллельная очередь это «быстрее всегда». Десятки одновременных задач раздувают пул потоков, и приложение начинает тормозить сильнее, чем на последовательной очереди.
Обновляют интерфейс из фоновой очереди. Иногда это даже работает, а потом падает без внятного стека.
Не знают про барьер: queue.async(flags: .barrier) на параллельной очереди даёт схему «много читателей, один писатель».