Детальный обзор различных очередей и их свойств в GCD
Очереди в Grand Central Dispatch (GCD) — это основа многопоточного программирования в iOS. Понимание различных типов очередей и их характеристик позволяет создавать эффективные и отзывчивые приложения. В этой статье мы глубоко рассмотрим все виды очередей GCD и научимся выбирать оптимальный вариант для конкретных задач.
Содержание:
Фундаментальные типы очередей в GCD
GCD предоставляет два основных типа очередей: последовательные (serial) и параллельные (concurrent). Каждый тип имеет свои уникальные характеристики и области применения.
Последовательные очереди (Serial Queues)
Последовательные очереди выполняют только одну задачу за раз, в порядке FIFO (First-In-First-Out). Новая задача начинается только после завершения предыдущей.
// Создание пользовательской последовательной очереди
let serialQueue = DispatchQueue(label: "com.myapp.serialQueue")
// Добавление задач
serialQueue.async {
print("Задача 1 запущена")
// Будет выполнена полностью, прежде чем начнется Задача 2
sleep(2)
print("Задача 1 завершена")
}
serialQueue.async {
print("Задача 2 запущена")
sleep(1)
print("Задача 2 завершена")
}
Ключевые свойства последовательных очередей:
- Гарантированный порядок выполнения задач
- Отсутствие гонок данных внутри очереди
- Идеальны для доступа к общим ресурсам, требующим синхронизации
Параллельные очереди (Concurrent Queues)
Параллельные очереди могут выполнять несколько задач одновременно. Задачи запускаются в порядке FIFO, но могут завершаться в произвольном порядке.
// Создание пользовательской параллельной очереди
let concurrentQueue = DispatchQueue(label: "com.myapp.concurrentQueue", attributes: .concurrent)
// Добавление задач
concurrentQueue.async {
print("Задача 1 запущена")
sleep(2)
print("Задача 1 завершена")
}
concurrentQueue.async {
print("Задача 2 запущена")
sleep(1)
print("Задача 2 завершена") // Может завершиться раньше, чем Задача 1
}
Ключевые свойства параллельных очередей:
- Одновременное выполнение нескольких задач
- Максимальное использование доступных ресурсов CPU
- Отсутствие гарантий порядка завершения задач
Системные очереди и их особенности
GCD предоставляет набор предопределенных глобальных очередей с различными приоритетами, а также специальную главную очередь.
Главная очередь (Main Queue)
let mainQueue = DispatchQueue.main
mainQueue.async {
// Код, обновляющий пользовательский интерфейс
updateUI()
}
Характеристики главной очереди:
- Выполняется в главном потоке приложения
- Является последовательной очередью
- Предназначена исключительно для обновления UI и обработки пользовательских взаимодействий
- Блокировка этой очереди приводит к зависанию интерфейса
Глобальные очереди с различными QoS (Quality of Service)
// Получение глобальных очередей с разными приоритетами
let userInteractiveQueue = DispatchQueue.global(qos: .userInteractive)
let userInitiatedQueue = DispatchQueue.global(qos: .userInitiated)
let defaultQueue = DispatchQueue.global(qos: .default)
let utilityQueue = DispatchQueue.global(qos: .utility)
let backgroundQueue = DispatchQueue.global(qos: .background)
QoS определяет приоритет задач:
userInteractive — наивысший приоритет для задач, связанных с UI:
- Анимации
- Обработка жестов
- Быстрые UI-обновления
userInitiated — для задач, инициированных пользователем:
- Открытие документа
- Обработка клика по кнопке "Загрузить"
- Задачи, требующие быстрой обратной связи
default — стандартный приоритет:
- Используется по умолчанию, если не указано иное
utility — для длительных задач с индикатором прогресса:
- Загрузка или импорт данных
- Вычисления с отображением прогресса
background — низший приоритет для незаметных пользователю задач:
- Индексация
- Синхронизация
- Резервное копирование
Настройка пользовательских очередей
При создании собственных очередей GCD предлагает гибкие возможности для настройки их поведения.
Основные атрибуты при создании очереди
// Создание очереди с дополнительными атрибутами
let customQueue = DispatchQueue(
label: "com.myapp.customQueue", // Уникальный идентификатор
qos: .userInitiated, // Приоритет
attributes: [.concurrent, .initiallyInactive], // Дополнительные атрибуты
autoreleaseFrequency: .workItem, // Частота автоосвобождения
target: DispatchQueue.global(.default) // Целевая очередь
)
// Активация очереди
customQueue.activate()
Ключевые параметры настройки:
- label — уникальный идентификатор очереди, полезный для отладки
- qos — приоритет задач в очереди
- attributes — дополнительные характеристики:
.concurrent
— делает очередь параллельной.initiallyInactive
— создает неактивную очередь, требующую ручной активации
- autoreleaseFrequency — частота автоосвобождения объектов Objective-C:
.inherit
— наследует от целевой очереди.workItem
— освобождает пул после каждой задачи.never
— никогда не освобождает автоматически
- target — целевая очередь, на которой будут выполняться задачи
Расширенные техники работы с очередями
Эффективная работа с очередями требует глубокого понимания их дополнительных возможностей.
Target Queues (Целевые очереди)
Целевые очереди позволяют создавать иерархии очередей с наследованием свойств.
let parentQueue = DispatchQueue(label: "com.myapp.parentQueue", qos: .userInitiated)
let childQueue = DispatchQueue(label: "com.myapp.childQueue", target: parentQueue)
// Задачи в childQueue будут иметь QoS от parentQueue
childQueue.async {
performTask()
}
Установка приоритета отдельных задач
Можно переопределить QoS для конкретных задач независимо от очереди:
let queue = DispatchQueue.global(qos: .utility)
// Выполнение с повышенным приоритетом
queue.async(qos: .userInitiated) {
performHighPriorityTask()
}
Адаптация под нагрузку системы с помощью DispatchSourceTimer
GCD умеет адаптироваться к системной нагрузке для оптимального расхода энергии:
let timer = DispatchSource.makeTimerSource(queue: DispatchQueue.global())
timer.schedule(deadline: .now(), repeating: .seconds(1), leeway: .milliseconds(100))
timer.setEventHandler {
// Выполняется примерно каждую секунду с допустимым отклонением 100мс
performPeriodicTask()
}
timer.resume()
Не забудьте загрузить приложение iJun в AppStore и подписаться на мой YouTube канал для получения дополнительных материалов по iOS-разработке.