В чем разница между синхронным (Sync) выполнением и последовательной (Serial) очередью в GCD?

«В чем разница между синхронным (Sync) выполнением и последовательной (Serial) очередью в GCD?» — вопрос из категории Многопоточность, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Sync/Async и Serial/Concurrent — это ортогональные характеристики в Grand Central Dispatch.

1. Тип очереди (качество):

  • Serial (последовательная): Задачи выполняются строго одна за другой (FIFO).
  • Concurrent (параллельная): Задачи могут выполняться одновременно на нескольких потоках.

2. Способ отправки задачи (модальность):

  • Sync (синхронно): Блокирует текущий поток до полного выполнения задачи.
  • Async (асинхронно): Отправляет задачу и немедленно продолжает выполнение в текущем потоке.

Примеры:

let serialQueue = DispatchQueue(label: "com.example.serial")
let concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)

// Serial + Async: Порядок гарантирован, текущий поток не блокируется
serialQueue.async { print("Task 1") }
serialQueue.async { print("Task 2") } // Начнется только после Task 1

// Concurrent + Async: Порядок не гарантирован, задачи могут выполняться параллельно
concurrentQueue.async { print("Task A") }
concurrentQueue.async { print("Task B") } // Может начаться до завершения Task A

// Sync (опасно!): Блокирует текущий поток. Может привести к deadlock на serial очереди.
serialQueue.sync { 
    print("Это выполнится, но поток будет ждать")
    // serialQueue.sync { ... } // DEADLOCK! Очередь ждет сама себя.
}

Основное правило: Используйте async по умолчанию. Sync применяйте осторожно, в основном для синхронизации доступа к общим данным или когда следующий код зависит от результата задачи.