← Назад к вопросам
Какие знаешь виды очередей?
2.0 Middle🔥 241 комментариев
#Многопоточность и асинхронность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Виды очередей в Swift и iOS
Типы очередей (Dispatch Queues)
1. Main Queue — главная очередь
// Основная очередь для UI операций
DispatchQueue.main.async {
// Все UI обновления здесь
self.label.text = "Updated"
self.imageView.image = newImage
}
// Синхронно (опасно!)
DispatchQueue.main.sync { // Может привести к deadlock
self.label.text = "Updated"
}
Характеристики:
- Serial queue (одна операция за раз)
- Запускается на главном потоке
- Для всех UI операций
- Обновления экрана синхронизированы с refresh rate (60/120 FPS)
2. Global Queues — глобальные очереди
// QoS (Quality of Service) levels
DispatchQueue.global(qos: .userInteractive).async {
// Максимальный приоритет, для UI-related work
}
DispatchQueue.global(qos: .userInitiated).async {
// Высокий приоритет, пользователь ждет результат
let data = fetchDataFromAPI()
DispatchQueue.main.async {
self.updateUI(with: data)
}
}
DispatchQueue.global(qos: .default).async {
// Стандартный приоритет
}
DispatchQueue.global(qos: .utility).async {
// Низкий приоритет, долгие операции
let result = expensiveComputation()
}
DispatchQueue.global(qos: .background).async {
// Минимальный приоритет, фоновые задачи
let backup = createBackup()
}
QoS Levels:
┌─────────────────────────────────────────────┐
│ .userInteractive │ Главное UI, ~25ms │
├─────────────────────────────────────────────┤
│ .userInitiated │ Действия пользователя │
├─────────────────────────────────────────────┤
│ .default │ Стандартный приоритет │
├─────────────────────────────────────────────┤
│ .utility │ Долгие операции │
├─────────────────────────────────────────────┤
│ .background │ Фоновые задачи │
└─────────────────────────────────────────────┘
3. Custom Queues — пользовательские очереди
// Serial queue (одна операция за раз)
let serialQueue = DispatchQueue(label: "com.example.serial")
serialQueue.async {
print("1")
}
serialQueue.async {
print("2")
}
serialQueue.async {
print("3")
}
// Вывод: 1, 2, 3 (в таком порядке, не параллельно)
// Concurrent queue (несколько операций одновременно)
let concurrentQueue = DispatchQueue(
label: "com.example.concurrent",
attributes: .concurrent
)
concurrentQueue.async {
print("1")
}
concurrentQueue.async {
print("2")
}
concurrentQueue.async {
print("3")
}
// Вывод: может быть 1,2,3 или 2,1,3 или 3,1,2 (случайный порядок)
Различия между Serial и Concurrent
// SERIAL — очень важно для data consistency
let dbQueue = DispatchQueue(label: "com.example.database")
var count = 0
dbQueue.async {
count += 1 // Выполняется первым
}
dbQueue.async {
count += 1 // Выполняется вторым
}
// count = 2 (всегда предсказуемо)
// CONCURRENT — может быть race condition
let concurrentQueue = DispatchQueue(
label: "com.example.concurrent",
attributes: .concurrent
)
var unsafeCount = 0
concurrentQueue.async {
unsafeCount += 1 // Может конфликтовать
}
concurrentQueue.async {
unsafeCount += 1 // С этим
}
// unsafeCount = 1 или 2? (непредсказуемо)
OperationQueue
// Высокоуровневая абстракция над GCD
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1 // Serial
queue.name = "com.example.operationQueue"
queue.qualityOfService = .userInitiated
// BlockOperation
let operation = BlockOperation {
let data = fetchData()
print(data)
}
operation.completionBlock = {
print("Operation completed")
}
queue.addOperation(operation)
// Custom Operation
class DataFetchOperation: Operation {
var data: [String] = []
override func main() {
if isCancelled { return }
data = fetchDataFromAPI()
if isCancelled { return }
processData(data)
}
}
let customOp = DataFetchOperation()
queue.addOperation(customOp)
Async/Await (Modern Swift)
// Вместо DispatchQueue используем async/await
func loadData() async {
// Автоматически на background потоке
let data = try await fetchData()
// Явный переход на main для UI
await MainActor.run {
self.updateUI(with: data)
}
}
// Или используя @MainActor
@MainActor
func updateUI(with data: Data) {
self.label.text = data.description
}
Task {
let data = try await loadData()
await updateUI(with: data) // Автоматически на main
}
Практические примеры
Пример 1: Network Request с UI update
func loadUserProfile() {
// Запрос на background
DispatchQueue.global(qos: .userInitiated).async {
let user = self.fetchUser() // Long operation
// Update UI на main
DispatchQueue.main.async {
self.nameLabel.text = user.name
self.avatarImage.image = user.avatar
}
}
}
// Лучше с async/await
func loadUserProfile() async {
let user = await fetchUser() // Background
await MainActor.run { // Main thread
self.nameLabel.text = user.name
self.avatarImage.image = user.avatar
}
}
Пример 2: Database Operations (Serial)
class DatabaseManager {
private let dbQueue = DispatchQueue(
label: "com.example.database",
attributes: [] // Serial
)
func saveUser(_ user: User) {
dbQueue.async {
// Всегда выполняется в порядке очереди
let statement = "INSERT INTO users VALUES (...)"
self.execute(statement)
}
}
func getAllUsers() -> [User] {
// Проблема: нужен sync для получения результата
var result: [User] = []
dbQueue.sync {
result = self.query("SELECT * FROM users")
}
return result
}
}
Пример 3: Image Processing (Concurrent)
let imageQueue = DispatchQueue(
label: "com.example.image",
attributes: .concurrent
)
func processImages(_ images: [UIImage]) {
for image in images {
imageQueue.async {
let processed = applyFilter(image)
DispatchQueue.main.async {
self.displayImage(processed)
}
}
}
}
Barrier в Concurrent Queues
// Для синхронизации в concurrent очереди
let concurrentQueue = DispatchQueue(
label: "com.example.concurrent",
attributes: .concurrent
)
var data: [String] = []
// Чтение
concurrentQueue.async {
_ = data // Может выполняться параллельно
}
// Запись с barrier
concurrentQueue.async(flags: .barrier) {
data.append("new item") // Выполняется исключительно
}
// Снова чтение
concurrentQueue.async {
_ = data // Гарантированно видит обновленные данные
}
Правила использования
Используй DispatchQueue когда:
✅ Нужна простая асинхронность
✅ Легкие задачи
✅ Нужна высокая производительность
Используй OperationQueue когда:
✅ Нужны зависимости между операциями
✅ Нужна отмена (cancellation)
✅ Нужны приоритеты
Используй async/await когда:
✅ Swift 5.5+
✅ Читаемость важнее
✅ Новый код
Выводы
- Main Queue для UI
- Global Queues для network/computations
- Custom Serial для синхронизации данных
- Custom Concurrent для параллельной обработки
- async/await в новом коде вместо callbacks