В чем разница между GCD и async/await в Swift?

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

Ответ

GCD (Grand Central Dispatch) — низкоуровневый C-API для управления потоками через очереди. async/await — высокоуровневая абстракция Swift Concurrency для асинхронного программирования.

Сравнительная таблица:

Аспект GCD async/await
Уровень абстракции Низкий (потоки, очереди) Высокий (задачи, продолжения)
Синтаксис Closures, callback hell Последовательный код с await
Управление потоками Ручное (DispatchQueue.main/global) Автоматическое (cooperative pool)
Отмена задач DispatchWorkItem.cancel() Task.cancel(), проверка Task.isCancelled
Обработка ошибок Через completion handlers Встроенная через throw/try/catch
Приоритеты QoS (.userInteractive, .background) TaskPriority (.high, .medium, .low)
Состояние гонки Возможно без синхронизации Предотвращается через Actors

Пример GCD:

func fetchData(completion: @escaping (Result<Data, Error>) -> Void) {
    DispatchQueue.global(qos: .userInitiated).async {
        let data = // ... загрузка
        DispatchQueue.main.async {
            completion(.success(data))
        }
    }
}

Пример async/await:

func fetchData() async throws -> Data {
    // Автоматически выполняется в background pool
    let data = try await downloadFromNetwork()
    return data
}

// Использование:
Task {
    do {
        let data = try await fetchData()
        await MainActor.run {
            updateUI(with: data) // Автоматически на главном потоке
        }
    } catch {
        handleError(error)
    }
}

Ключевые преимущества async/await:

  1. Читаемость — линейный код вместо вложенных closures
  2. Безопасность — интеграция с Actors для потокобезопасности
  3. Производительность — cooperative threads вместо создания потоков
  4. Интеграция — работа с @MainActor, TaskGroup, AsyncSequence

Когда использовать GCD:

  • Низкоуровневый контроль над потоками
  • Работа с legacy кодом
  • Таймеры (DispatchSourceTimer)
  • Барьеры для чтения/записи