Многопоточность в языке Swift | Статья в журнале «Молодой ученый»

Отправьте статью сегодня! Журнал выйдет 1 мая, печатный экземпляр отправим 5 мая.

Опубликовать статью в журнале

Автор:

Рубрика: Информационные технологии

Опубликовано в Молодой учёный №12 (354) март 2021 г.

Дата публикации: 22.03.2021

Статья просмотрена: 17 раз

Библиографическое описание:

Антонов, В. А. Многопоточность в языке Swift / В. А. Антонов. — Текст : непосредственный // Молодой ученый. — 2021. — № 12 (354). — С. 15-18. — URL: https://moluch.ru/archive/354/79326/ (дата обращения: 21.04.2021).



В статье рассмотрим основной способ выполнять код асинхронно, который используется в iOS приложениях. Подробно разобран основной функционал Grand Central Dispatch (GCD) и сценарии, в которых можно реализовать многопоточность с его помощью.

Ключевые слова: программирование, многопоточность, мобильная разработка, Swift, iOS приложения.

Swift — это молодой и быстроразвивающийся язык, который был разработан компанией Apple в 2014 году и используется для разработки iOS и MacOS приложений. Является прямым приемником языка Objective-C и задумывался как более легкий для чтения и устойчивый к ошибкам программиста язык. В языке Swift явно прослеживается заимствование лучших практик из языков Objective-C, Python и C#.

Многопоточность — это свойство программы или алгоритма состоять из нескольких потоков, выполняющихся параллельно. Это означает, что некоторые задачи могут выполняться одновременно, что может позволить достичь более эффективного использования ресурсов устройства и не приведет к ошибкам в коде.

Разные языки используют совершенно разные механизмы работы с параллелизмом. Например, в C# для этого используется async/await, в то время как в Swift для работы с тем, что выполняется в другом потоке, используются замыкания. Изначально Swift 5 планировал реализовать более распространенный шаблон async/await, но он был удален из спецификации до следующего релиза.

Grand Central Dispatch (GCD) — это реализация Apple библиотеки libdispatch языка C. Ее цель в зависимости от ресурсов поставить в очередь задачи, которые могут выполняться параллельно, а затем выполнять задачи на доступном ядре процессора.

Благодаря тому, что GCD использует потоки в своей реализации, то разработчику не нужно беспокоиться о том, как управлять ими самостоятельно.

Все задачи, которыми управляет GCD, помещаются в управляемые очереди. Каждая задача, которую вы ставите в очередь, затем выполняется в пуле потоков, полностью управляемых системой.

Код, отправленный в очередь, может выполняться синхронно или асинхронно. При синхронном выполнении задачи ваше приложение будет ждать и блокировать текущий цикл выполнения, пока выполнение текущей задачи не завершится, прежде чем перейти к следующей. С другой стороны, асинхронно выполняемая задача не требует ожидания её завершения и работает независимо, не блокируя работу приложения.

Для того, чтобы используя GCD отправить любую долгосрочную задачу, не связанную с UI приложения, в фоновый режим необходимо добавить несколько строчек кода:

В этом коде создадим очередь, отправляем в неё наш код для выполнения асинхронно в фоновом потоке и при его завершении возвращаемся в основной поток для обновления UI приложения.

Есть много преимуществ в том, чтобы разделять работу вашего приложения на несколько потоков, давайте рассмотрим их в таблице 1.

Таблица 1

Преимущества использования многопоточности в разработке

Быстрое выполнение

Запуск задач на разных потоках дает возможность выполнять их одновременно, что позволит выполнить их быстрее.

Отзывчивость

Выполняя в основном потоке только задачи связанные с UI пользователи не заметят, что приложение выполняет фоновые задачи.

Оптимизация ресурсов

Использование потоков позволяет экономить ресурсы устройства и выполнять большее количество задач

В iOS нет нужды создавать потоки, операционная система самостоятельно создает потоки, используя более высокие абстракции.

Для этого Apple предоставляет специальное API для управления потоками.

Для работы с потоками необходимо создать DispatchQueue:

let queue = DispatchQueue(label: “com.company.app.networking”)

Когда вы создаете очередь, операционная система может создать или назначить один или более потоков для очереди. Если существующие потоки доступны, то их можно использовать повторно. Если нет, то тогда iOS создаст их при необходимости.

Параметр label должен быть уникальным и используется как id.

Когда ваше приложение запускается, главная очередь отправки создается автоматически. Это последовательная очередь, которая отвечает за интерфейс приложения. Вы никогда не должны выполнять что-то синхронное в основной очереди, если это не связано с нынешней работой интерфейса приложения. В противном случае, вы заблокируете интерфейс приложения и снизите его производительность.

Раннее упоминалось о том, что очереди бывают двух типов — последовательные и параллельные. Стандартный инициализатор, из примера выше, создает последовательную очередь, а для создания параллельной необходимо добавить соответствующий параметр:

let queue = DispatchQueue(label: “com.company.app.networking”, attributes:.concurrent)

Apple предоставляет 6 разных глобальных параллельных очередей, в целом называемые Quality of Service (QoS)

Используя параллельные очереди, отправка вам необходимо указать приоритет задачи. Помните, что работа с более высоким приоритетом должна выполняться быстрее и скорее потребует больше системных ресурсов и энергии, чем работа с более низким приоритетом.

Если вы хотите использовать параллельную очередь, но не хотите создавать свою собственную, метод global класса DispatchQueue предлагает на выбор одну из предустановленных глобальных очередей.

let queue = DispatchQueue.global(qos:.userInteractive)

В Таблице 2 приведены 6 классов качества сервиса Apple.

Таблица 2

Стандартные классы качества сервиса

.userInteractive

Рекомендуется использовать для задач, с которыми напрямую взаимодействует пользователь.

.userInitiated

Эта очередь используется, когда пользователь отправляет задачу через UI, которая должна выполниться незамедлительно, но может быть выполнения асинхронно. К примеру, вам нужно открыть документ или прочитать данные из локальной базы данных.

.utility

Эту очередь рекомендуется использовать для задач, которые обычно включают в себя индикатор прогресса, такие как длительные вычисления или работа в сети.

.background

Для задач, которые напрямую не связаны с пользователями, которые не требуют пользовательского взаимодействия и не требовательны к времени выполнения.

.default

Является стандартным значением для аргумента qos.

.unspecified

Существует для поддержки устаревших API. Стоит знать об её существовании, но использовать самостоятельно не рекомендуется.

Все перечисленные выше глобальные очереди работают параллельно.

Если вы хотите создать свою собственную параллельную очередь, вам необходимо указать соответствующие параметры при инициализации:

let queue = DispatchQueue(label: “com.company.app.networking”, qos:.userInitiated, attributes:.concurrent)

Но несмотря на то, что вы указали для вашей очереди её уровень приоритета, iOS следит за типом задач, отправляемых в эту очередь и при необходимости, может изменить её приоритет.

Для добавления задач в очередь DispatchQueue предоставляет для этого методы sync и acync.

Иногда вместо того, чтобы просто отправить задачу в очередь, вам может потребоваться обработать группу задач. Они не должны работать одновременно, но вам необходимо отследить, когда они все будут завершены. Для этого Apple предоставляет DispatchGroup.

Для начала необходимо инициализировать саму группу. Задачу, которую вы хотите отслеживать, как часть группы необходимо размещать в теле метода async в любой очереди.

Диспетчер очередей из коробки понимает, как работать с диспетчером групп и заботиться об уведомлении системы, что задача была выполнена. В этом случае выполненная означает, что блок кода запустился и все идет своим чередом. Почему это важно? Потому что если вы запускаете асинхронный метод внутри замыкания, то замыкание завершится до того, как будет завершено выполнение внутреннего асинхронного метода.

Для того чтобы сделать так, чтобы задача не была завершена, пока все внутренние асинхронные задачи не будут завершены, следует использовать enter и leave методы DispatchGroup:

Вызывая group.enter() позволяете диспетчеру групп понять, что запущен еще один блок кода, который должен фиксироваться в общем статусе завершения группы. Дополнительно необходимо уведомить диспетчер групп о завершении задачи соответствующим вызовом group.leave(), без этого диспетчер групп не сможет зафиксировать завершение и изменить счетчик.

В данной статье проведен обзор основных методов работы с многопоточностью, которые используются в разработке мобильных iOS приложений на языке Swift. Используя многопоточность, программисты получают возможность создавать более быстрые и сложные интерфейсы, которые будут радовать конечного пользователя своим быстродействием и откликом.

Основные термины (генерируются автоматически): GCD, очередь, задача, API, диспетчер групп, ваше приложение, поток, операционная система, основной поток, последовательная очередь.


Ключевые слова

программирование, Swift, многопоточность, мобильная разработка, iOS приложения
Задать вопрос