Использование корутин в Kotlin для лёгкого распараллеливания алгоритмов
Корутины похожи на потоки: они задают последовательность выполнения команд со своим стеком, своими переменными. Главное отличие корутин от потоков в том, что корутины умеют задерживать свое выполнение для того, чтобы дождаться результата от другой корутины. Что это даёт Android-программисту? Расскажет Виктор Кинько, Android-разработчик BytePace.
Стоит заметить, что корутины это не только синтаксический сахар - из-за того, что они реализованы через легковесные потоки, их создание занимает куда меньше время, чем создание классических тредов, а значит, в системе с высоким параллелизмом они будут более выгодны в плане быстродействия. Но это лишь в теории.
На практике передо мной стояла тривиальная задача рефакторинга кода. Условия задачи:
• на экране есть Google-карта
• на карте нужно отобразить маркеры, соответствующие точкам в пути
• точки заданы текстовыми адресами.
Сложности и ход выполнения:
• Google-карту для начала нужно инициализировать. Это делается с помощью метода getMapAsync в отдельном потоке
• Для получения географических координат точек пути нужно использовать Geocoder, который выполняет интернет-запрос в отдельном потоке
• После получения карты на неё можно добавлять маркеры, если они уже получены. Это должно делаться в главном потоке.
В итоге после вызволения логики в отдельный класс передо мной был такой код:
Перепишем этот код с использованием корутин:
Основное преимущество, которое мы получили, использовав корутины, - легкость модификации для распараллеливания.
Но это неэффективно. Мы не инициализируем карту до того как не получены координаты точек. При слабой работе сети интернет мы можем ждать результат до самого таймаута.
С другой стороны, если поменять местами функции и вызвать сперва getGoogleMap, то на слабом телефоне придётся ждать пока инициализируется карта, а потом ещё и ждать результата запроса.
Лучший способ организации этого процесса - запустить две функции параллельно и передать результаты в третью:
Конечно же, это только способ организации кода и потоков, такой же как RX или просто цепочка вызовов. Но оцените, насколько просто удалось поменять ход выполнения, и насколько просто читается код.
Если применить этот пример к более сложным алгоритмам, то можно добиться значительного прироста производительности, а значит, улучшить опыт пользователя.
Спасибо за внимание!
Больше статей в нашем блоге: