Как количество одновременно выполняемых задач (throughput) зависит от типа очереди (GCD) и числа потоков?

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

Ответ

Пропускная способность (tasks/time) определяется типом очереди и доступными системными ресурсами (ядрами CPU), а не просто количеством потоков.

1. Serial (последовательная) очередь:

  • Выполняет задачи строго по одной, в порядке добавления (FIFO).
  • Throughput = 1 задача / время_выполнения_задачи.
  • Добавление потоков не увеличивает производительность.
let serialQueue = DispatchQueue(label: "com.example.serial")
// Все задачи выполнятся последовательно, одна за другой.

2. Concurrent (параллельная) очередь:

  • Может запускать несколько задач одновременно, используя пул потоков.
  • Максимальный параллелизм ограничен системой (например, ProcessInfo.processInfo.activeProcessorCount).
  • Throughput ≈ min(число_ядер, число_задач_в_очереди) / среднее_время_задачи.
let concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)
// На 6-ядерном CPU до 6 задач могут выполняться физически параллельно.

3. Global Queues & QoS: Системные очереди (DispatchQueue.global()) являются concurrent. Качество обслуживания (QoS) влияет на приоритет получения системных ресурсов, но не на абсолютный лимит параллелизма.

Вывод: Для CPU-bound задач параллелизм ограничен ядрами CPU. Для I/O-bound задач можно добиться большего overlap операций ввода-вывода, но активных потоков, выполняющих код, всё равно будет не больше доступных ядер.