Как работает отмена корутин
Вопрос
Расскажи подробно, как работает отмена корутин и какие ошибки с ней делают.
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
cancel() переводит Job в Cancelling, реальная остановка в точке приостановки
Отмена кооперативная: в циклах isActive, ensureActive, yield
Реализована через CancellationException, его нельзя глотать
Отмена распространяется на детей
NonCancellable для очистки в finally
withTimeout бросает TimeoutCancellationException
Что могут спросить следом
- Почему
runCatchingв корутинах опасен? - Как отменить блокирующий вызов, например чтение сокета?
- Чем
withTimeoutотличается отwithTimeoutOrNull?
Разбор
Отмена в корутинах кооперативная. Вызов job.cancel() ничего не прерывает силой: он переводит Job в состояние отмены и отменяет детей. Сама корутина остановится, когда дойдёт до точки приостановки, потому что suspend-функции из kotlinx.coroutines проверяют отмену и бросают CancellationException. Если корутина крутит вычислительный цикл без suspend-вызовов, она отмену не заметит, поэтому в таких циклах проверяют isActive или вызывают ensureActive(). Блокирующие вызовы вроде чтения сокета отмена тоже не прервёт, их закрывают вручную или через runInterruptible. Поскольку отмена это исключение, его нельзя глотать: catch (e: Exception) или runCatching вокруг suspend-кода перехватят его, и отменённая корутина продолжит работу. Правильно ловить конкретные типы или перебрасывать CancellationException. В finally после отмены suspend-функции сразу бросят исключение, поэтому для очистки используют withContext(NonCancellable). Таймауты устроены так же: withTimeout бросает TimeoutCancellationException, withTimeoutOrNull возвращает null.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.