В чём разница между последовательной (serial) и параллельной (concurrent) очередью в GCD?

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

Ответ

Разница заключается в порядке выполнения задач и использовании потоков.

Характеристика Serial Queue (Последовательная) Concurrent Queue (Параллельная)
Выполнение задач Строго по порядку, одна за другой. Одновременно, насколько позволяет система.
Потоки Использует один поток (но не обязательно всегда один и тот же системный поток). Использует несколько потоков из пула.
Главное преимущество Гарантированная потокобезопасность для общих ресурсов. Производительность за счёт параллелизма.
Типичное применение Синхронизация доступа к общим данным, порядок операций. Выполнение независимых, ресурсоёмких задач.

Практический пример:

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

// Задачи на Serial Queue выполнятся суммарно за ~3 секунды.
serialQueue.async { sleep(1); print("Serial Task 1 done") }
serialQueue.async { sleep(1); print("Serial Task 2 done") } // Ждёт окончания Task 1
serialQueue.async { sleep(1); print("Serial Task 3 done") } // Ждёт окончания Task 2

// Задачи на Concurrent Queue выполнятся суммарно за ~1 секунду.
concurrentQueue.async { sleep(1); print("Concurrent Task 1 done") }
concurrentQueue.async { sleep(1); print("Concurrent Task 2 done") } // Запускается сразу
concurrentQueue.async { sleep(1); print("Concurrent Task 3 done") } // Запускается сразу

Ключевой вывод:

  • Быстрее для независимых задач — concurrent очередь.
  • Безопаснее для операций с общим состоянием — serial очередь (или concurrent с барьерами .barrier). Выбор зависит от конкретной задачи.