Этот месяц не был богат на события в мире инфосека, о которых бы мы не написали в новостях. Поэтому сегодняшний дайджест исключительно программерский. Итак, в этом выпуске: семь новых инструментов программиста и дизайнера, советы по написанию производительного приложения, Observable-поля и структурированный параллелизм в Kotlin, бенчмарки и, конечно же, подборка свежих библиотек.
 

Структурированный параллелизм в Kotlin

Structured concurrency — статья Романа Елизарова из JetBrains о новой возможности библиотеки kotlinx.coroutines 0.26.0, а точнее даже не возможности, а об изменении в подходе к написанию распараллеленного кода на Kotlin.

Суть новой функции проста. Представим, что у нас есть такой код:

fun requestSomeData() {
    launch(UI) {
        updateUI(performRequest())
    }
}

Функция создает новую корутину в основном потоке приложения (контекст UI), а затем запускает блокируемую (suspend) функцию performRequest, которая делает какую-то фоновую работу, не блокируя основной поток.

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

Как раз для этого и пригодится новая функция. Теперь корутины можно (и нужно) ограничить своего рода «областью действия». Например, если объявить активность, из которой вызывается функция requestSomeData, таким образом:

class MyActivity : AppCompatActivity(), CoroutineScope {
    ...
}

И слегка изменить саму функцию, исключив из нее контекст (UI):

fun requestSomeData() {
    launch {
        updateUI(performRequest())
    }
}

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

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

suspend fun loadAndCombine(name1: String, name2: String): Image { 
    val deferred1 = async { loadImage(name1) }
    val deferred2 = async { loadImage(name2) }
    return combineImages(deferred1.await(), deferred2.await())
}

Хорошо и удобно, но есть проблемы. Что, если будет завершена корутина, вызывавшая эту функцию? Мы получим две корутины-беспризорника. А что, если загрузка одного изображения закончится неудачей? Второе изображение продолжит загружаться, хотя нам это уже не нужно.

Выход:

suspend fun loadAndCombine(name1: String, name2: String): Image =
    coroutineScope { 
        val deferred1 = async { loadImage(name1) }
        val deferred2 = async { loadImage(name2) }
        combineImages(deferred1.await(), deferred2.await())
    }

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


Оставить мнение