3.1 C
Москва
Пятница, 17 января, 2025

Многопоточность: что это, использование в мобильных приложениях, как оптимизировать производительность

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

Многопоточность: что это, использование в мобильных приложениях, как оптимизировать производительность https://rb.ru/story/multithreading/ Автор: Владислав Афонин https://rb.ru/author/vafonin/ Подписаться на RB.RU в Telegram

  • Что такое многопоточность?
  • Основные концепции многопоточности
  • Компоненты многопоточности в Android
  • Создание главного потока
  • Как происходит создание нового потока?
    • Android. Использовать класс Thread
    • Android. Применение ExecutorService
    • Android. Корутины
    • iOS. Использование Thread
  • Примеры использования многопоточности
  • Один поток или многопоточность?
  • Итог

Что такое многопоточность?

Multithreadingот англ. «многопоточность» — это способность программы выполнять несколько потоков одновременно. Он представляет собой наименьшую единицу обработки, которая может быть запущена внутри процесса. 

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

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

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

Многопоточность используется, чтобы:

  • Уменьшить время отклика приложений.
  • Использовать вычислительные ресурсы устройства наиболее эффективно.
  • Выполнять ресурсоемкие операции без блокировки основного пользовательского интерфейса.

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

Основные концепции многопоточности

Поток и процесс. 

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

Поток — это «легковесная» единица выполнения внутри процесса, которая разделяет память и ресурсы с другими потоками того же процесса. 

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

Конкуренция (concurrency). 

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

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

Параллелизм.

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

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

Синхронизация. 

Когда используются несколько потоков, то может возникнуть конфликт, если они одновременно обращаются к одним и тем же ресурсам, например, к переменной или файлу. 

Чтобы избежать таких столкновений, применяются механизмы синхронизации: Мьютексы (mutex) — блокируют ресурс, пока один поток работает с ним.

Семафоры (semaphores) — ограничивают количество каналов, которые могут одновременно получить доступ к ресурсу.

Состояние гонки (race condition).

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

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

Deadlock (Взаимная блокировка).

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

Например, поток A захватывает ресурс X и ждет источник Y, в то время как канал B захватывает резерв Y и ждет ресурс X.

Планировщик потоков (thread scheduler).

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

Переключение контекста (context switching).

Происходит, когда процессор переходит между потоками. Это действие сохраняет состояния текущего элемента и загрузку состояния следующего.

Пулы потоков (Thread Pools). 

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

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

Компоненты многопоточности в Android

В ОС Android используется несколько компонентов для организации и управления потоками.

Рассмотрим основные компоненты многопоточности:

  • Thread. 

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

Например, вы можете использовать Thread для загрузки данных из интернета, чтобы не блокировать основной поток (UI). Однако прямое использование Thread требует внимательного управления, чтобы избежать ошибок.

  • Handler и Looper. 

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

Например, можно использовать их для обновления пользовательского интерфейса после завершения фона задачи.

  • AsyncTask. 

Это упрощенный способ выполнения задач в фоне. Например, AsyncTask может быть использован для загрузки изображения с сервера. Однако в новых версиях Android его рекомендуют заменять другими инструментами, так как он имеет ограничения.

  • Executors. 

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

  • Coroutines. 

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

Читайте также: Что такое распределенная система — обзор распределенных систем и микросервисных архитектур

Примеры, как используются компоненты:

  1. Загрузка данных с сервера. Можете использовать Executors для создания пула потоков, где каждый поток будет обрабатывать загрузку файла.
  2. Обновление интерфейса. С помощью Handler можно передать данные из фонового потока в основной поток, чтобы показать пользователю статус задачи.
  3. Асинхронные операции. Корутину можно использовать для выполнения длительных операций, таких как запись данных в базу, без блокировки основного потока.
Читать также:
В App Store появилось бесплатное приложение Gemini — нейросети Google | RB.RU

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

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

Создание главного потока

Главный поток (его еще называют UI-поток) — это основной поток выполнения, который запускается при старте приложения. 

Вся работа, связанная с отрисовкой интерфейса и взаимодействием с пользователем, выполняется именно в этом потоке.

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

Главный поток создается автоматически при запуске приложения. Например:

  • В Android главный поток инициируется системой, как только приложение запускается. В нем работает метод onCreate() активности, где разработчик описывает, какие элементы должны быть отображены.
  • В iOS главный поток создается автоматически через библиотеку UIKit, которая управляет отображением интерфейса.

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

Как происходит создание нового потока?

В Android создание нового потока можно реализовать разными способами.

Android. Использовать класс Thread

Это самый простой способ. 

Например:

val newThread = Thread { // Выполняем задачу в новом потоке val result = fetchData() println(“Данные получены: $result”) newThread.start() 

Android. Применение ExecutorService

Этот подход помогает управлять несколькими потоками.

val executor = Executors.newSingleThreadExecutor() executor.execute { val data = fetchData() println(“Обработка данных: $data”) } executor.shutdown()

Android. Корутины 

Современный и удобный способ, особенно в Kotlin.

CoroutineScope(Dispatchers.IO).launch { val response = fetchData() println(“Ответ: $response”) }

В iOS для создания нового потока также есть несколько вариантов.

iOS. Использование Thread

let newThread = Thread { let data = fetchData() print(“Данные: (data)”) } newThread.start()

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

Пользователь вводит маршрут, и приложение отправляет запрос к серверу:

  1. Создаем новый поток для запроса. Чтобы интерфейс оставался плавным, запрос запускаем в фоне.
  2. Получаем данные и возвращаем их в основной поток. Результаты поиска передаются в основной поток для отображения на экране.

Полезные советы:

  1. Оптимизируйте количество потоков. Слишком много потоков могут замедлить приложение.
  2. Не забывайте завершать фоновые потоки. Например, используйте executor.shutdown().
  3. Обрабатывайте ошибки. Неудачные операции в фоновом потоке могут привести к краху приложения.

Примеры использования многопоточности

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

Собрали распространенные примеры многопоточности:

  • Сетевые запросы. 

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

Если выполнять их в главном потоке, интерфейс программы «замрет», что приведет к плохому пользовательскому опыту.

  • Работа с базой данных. 

Операции с локальными БД, такими как SQLite или Room, могут быть ресурсоемкими. Чтобы сохранять, читать или обновлять сведения в таких базах рекомендуется использовать фоновые потоки.

  • Когда обрабатываются большие объемы информации. 

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

  • Чтобы реализовать периодические задачи. 

В некоторых программах требуется выполнять определенные задания с регулярными интервалами времени, например, синхронизировать информацию с сервером. Это можно осуществлять помощью WorkManager в Android, который работает в фоновом режиме.

  • Внедрение загрузчиков и апдейтеров. 

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

  • Чтобы реализовать потоковое воспроизведение. 

Музыкальные и видеоприложения, такие как «Яндекс.Музыка» или YouTube активно используют многозадачность для загрузки сведений по мере их проигрывания. Один канал отвечает за воспроизведение, а другой — за загрузку следующего фрагмента контента.

  • Уведомления в реальном времени. 

Сервисы для чатов, таких как WhatsApp или Telegram, используют фоновые потоки, чтобы поддерживать соединения с сервером и доставлять сообщения сразу.

  • Игры и графика. 

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

Читайте также: Метрики успешности мобильных приложений — современные показатели, которые необходимо отслеживать

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

Один поток или многопоточность?

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

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

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

Когда программа включает выполнение нескольких задач одновременно — будь то загрузка контента, работа с API или обработка информации в реальном времени, многозадачность становится необходимой.

Она позволяет разделить задачи между потоками, где каждый из них выполняет свою функцию. Например, один поток может обрабатывать сетевые запросы, другой — обновлять базу данных, а третий — рисовать пользовательский интерфейс.

Читайте также: Приложения для хобби стали выполнять функцию социальных сетей

Важно помнить, что создание слишком большого количества потоков может ухудшить производительность устройства. Каждый элемент использует часть процессорного времени, а чрезмерное переключение между ними (context switching) создает дополнительные накладные расходы.

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

Итог

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

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

Фото на обложке: Freepik

НОВОЕ НА САЙТЕ