Введение в корутины
Обзорно знакомимся с корутинами — лёгким способом писать асинхронный код.
Корутина — лёгкая «приостанавливаемая» задача, которая позволяет писать асинхронный код в привычном последовательном стиле.
Когда программа ждёт ответа от сети или файла, можно либо заблокировать поток, либо организовать асинхронность. Корутины Kotlin делают второе просто и читаемо. Это обзорный урок: цель — понять идею, а не освоить всё.
suspend-функции
Функцию, которая умеет «приостанавливаться» и возобновляться позже, помечают словом suspend. Вызвать её можно только из другой корутины или suspend-функции.
import kotlinx.coroutines.*
suspend fun loadData(): String {
delay(1000) // неблокирующая пауза
return "Данные загружены"
}
fun main() = runBlocking {
println(loadData())
}Вывод:
Данные загружены
launch — запуск корутины
Билдер launch запускает новую корутину, которая работает параллельно с остальным кодом, не блокируя поток.
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(500)
println("Мир")
}
println("Привет")
}Вывод:
Привет Мир
Почему это «лёгкие» задачи
Главное преимущество — экономичность. Потоков операционной системы можно создать тысячи, и они тяжёлые. Корутин же можно запустить сотни тысяч: они не привязаны к отдельному потоку и во время паузы (например, delay) освобождают поток для другой работы.
| Поток (Thread) | Корутина |
| тяжёлый, дорогой | лёгкая, дешёвая |
| блокируется при ожидании | приостанавливается, освобождая поток |
| их тысячи | их сотни тысяч |
Как работает под капотом
Ключевое отличие delay от обычного «сна» потока (Thread.sleep) в том, что delay не блокирует поток: корутина приостанавливается, поток в это время выполняет другие задачи, а по истечении времени корутина возобновляется. Технически компилятор превращает suspend-функцию в конечный автомат: каждая точка приостановки — это место, где функция может «замереть» и продолжиться позже. Запускать корутины нужно внутри области (scope), которую в примерах задаёт runBlocking.
Частые ошибки
- Вызывать suspend-функцию из обычной. Её можно вызвать только из корутины или другой suspend-функции.
- Использовать
Thread.sleepвместоdelay.sleepблокирует поток, теряя смысл корутин. - Путать корутины и потоки. Корутина — это не поток, а лёгкая задача, которая может выполняться в любом потоке.
Итог
- Корутины позволяют писать асинхронный код в последовательном стиле.
suspend-функции умеют приостанавливаться и вызываются из корутин.launchзапускает корутину, не блокируя поток.delayприостанавливает корутину без блокировки потока — в этом ключевое отличие отThread.sleep.