Comments 9
Глупый вопрос, но почему ключевое слово для короутин именно suspend
? Оно ведь означает "приостановить". Почему бы не сделать что-нибудь более понятное, типа async
, asynchronous
, awaitable
, coroutine
?
suspend не является ключевым словом для корутин. Им помечают функции, которые как раз-таки могут прерываться.
Вот здесь есть ответ на ваш вопрос (по-моему в начале видео): https://www.youtube.com/watch?v=rB5Q3y73FTo
Отличная статья!
Было бы здорово увидеть более подробное описание того, как это вяжется с многопоточностью и планированием задач.
Ведь если я ничего не путаю, даже бесконечный цикл в suspend функции не вызывает зависания интерфейса если внутри самого цикла есть точка прерывания, это значит что в какой то момент вместо продолжения дробления данных в цикле state машины - она планирует эту задачу вероятно куда-то в handler.post на android и даёт тем самым прогрузить интерфейс, вот интересно узнать как эта часть работает. (или возможно dispatcher main потока каждую следующую итерацию планирует в post o.O)
Ну и вообще наверное по работе dispatcher - ов должно быть много интересного - там же получается наверное возможна ситуация, когда одна корутина в процессе выполнения переключилась на другой поток, а другая наоборот переключилась с другого на текущий, и планировщик должен запустить её и вот это все))
она планирует эту задачу вероятно куда-то в handler.post на android и даёт тем самым прогрузить интерфейс
Именно так.
Следите за руками: компилятор генерит имплементацию Continuation
для каждой suspend
функции. Эта имплементация наследуется от ContinuationImpl, где при вызове resumeWith()
в текущем контексте ищется ContinuationInterceptor, у которого вызывается методinterceptContinuation()
.
Идём далее, стандартные диспетчеры реализуют СontinuationInterceptor
, и в методе interceptContinuation()
они превращают переданный Continuation
в DispatchedContinuation
. DispatchedContinuation
нужен для 2 вещей: во-первых, сам по себе в конечном итоге наследуется от Runnable
, во-вторых, в resumeWith()
он ищет в контексте CoroutineDispatcher
и вызывает у него метод dispatch(context: CoroutineContext, block: Runnable)
с самим собой в качестве аргумента.
Дальше очень просто — в dispatch()
переданные раннаблы раскидываются по экзекьюторам (ну, на самом деле не очень просто, всякие балансировки и оптимизации тоже присутствуют). Default
и IO
диспетчеры используют пулы потоков, а Main
в Android использует Handler.
В рамках комментария, конечно, сложно нормально описать всю эту кухню, есть в планах сделать статью по этой теме, да всё никак руки не доходят.
Спасибо, в оригинальной статье этот момент не описывается и мне тоже "нехватило" этой инфы. Постараюсь найти по этой теме, что-нибудь в ближайшее время.
Хорошая статья. Хотелось бы добавить, что диспатчер может также закинуть исполнение корутины в другом потоке еще до того, как случился resume после COROUTINE_SUSPEND, что позволяет не блокировать текущий поток, если первые операции блокирующие.
Kotlin, как работает suspend под капотом