Очереди задач в Swift: от GCD до Swift Concurrency
В разработке под iOS и macOS управление параллельным выполнением кода — одна из ключевых задач. Очереди задач (queues) позволяют эффективно распределять нагрузку между потоками, не блокируя пользовательский интерфейс. В этом руководстве мы разберём три основных подхода: классический Grand Central Dispatch (GCD), абстракцию OperationQueue и современный механизм Swift Concurrency (async/await).
1. Grand Central Dispatch (GCD) — основа параллелизма
GCD — это низкоуровневая библиотека C, интегрированная в Swift. Она управляет пулом потоков и предоставляет два типа очередей:
- Serial (последовательные) — задачи выполняются одна за другой в порядке добавления.
- Concurrent (параллельные) — задачи запускаются одновременно, порядок завершения не гарантирован.
Пример создания и использования очереди:
import Foundation
// Создаём последовательную очередь
let serialQueue = DispatchQueue(label: "com.example.serial")
serialQueue.async {
print("Задача 1 началась")
sleep(1)
print("Задача 1 завершена")
}
serialQueue.async {
print("Задача 2 началась")
sleep(1)
print("Задача 2 завершена")
}
// Параллельная очередь
let concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)
concurrentQueue.async {
print("Параллельная задача A")
}
concurrentQueue.async {
print("Параллельная задача B")
}
Ключевые возможности GCD:
DispatchQueue.main— главная очередь (UI-поток).DispatchQueue.global(qos: .userInitiated)— глобальные очереди с приоритетом (QoS).dispatchGroup— синхронизация нескольких задач.dispatchSemaphore— контроль доступа к ресурсам.
2. OperationQueue — объектно-ориентированная абстракция
OperationQueue построена поверх GCD, но предоставляет более высокоуровневый API. Основные преимущества:
- Управление зависимостями между операциями.
- Отмена задач (cancel).
- Мониторинг состояния (isFinished, isExecuting).
- Максимальное количество параллельных операций.
Пример с использованием BlockOperation:
import Foundation
let operationQueue = OperationQueue()
operationQueue.maxConcurrentOperationCount = 2
let operation1 = BlockOperation {
print("Операция 1: загрузка данных")
sleep(2)
print("Операция 1 завершена")
}
let operation2 = BlockOperation {
print("Операция 2: обработка")
sleep(1)
print("Операция 2 завершена")
}
// Устанавливаем зависимость: операция 2 начнётся только после завершения операции 1
operation2.addDependency(operation1)
operationQueue.addOperations([operation1, operation2], waitUntilFinished: false)
// Отмена операции
operation1.cancel()
Когда использовать OperationQueue:
- Сложные цепочки задач с зависимостями.
- Необходимость тонкого контроля (пауза, отмена).
- Работа с KVO (Key-Value Observing) для мониторинга.
3. Swift Concurrency — современный подход (iOS 13+, macOS 10.15+)
Начиная с Swift 5.5, Apple представила встроенную поддержку асинхронного программирования через async/await, Task и TaskGroup. Это более безопасный и читаемый способ работы с параллелизмом.
Базовый пример:
import Foundation
func fetchUserData() async -> String {
// Имитация сетевого запроса
try? await Task.sleep(nanoseconds: 2 * 1_000_000_000)
return "User data loaded"
}
func processData() async {
let data = await fetchUserData()
print("Получено: \(data)")
}
// Запуск асинхронной задачи
Task {
await processData()
}
// Параллельное выполнение с TaskGroup
await withTaskGroup(of: String.self) { group in
for i in 1...3 {
group.addTask {
let result = await fetchUserData()
return "Задача \(i): \(result)"
}
}
for await result in group {
print(result)
}
}
Основные компоненты Swift Concurrency:
async— маркировка асинхронной функции.await— ожидание результата асинхронной операции.Task— единица асинхронной работы.TaskGroup—