resume и только после вызовы resume в колбэке может закинуть задачу на новый поток, но здесь блокирующая функция, которая никогда не вернет COUROUTINE_SUSPEND, следовательно никогда и не остановится, и следовательно выполняться будет в том потоке, который ее вызывал. Чувствую я что-то не понимаю про диспетчеры.
suspend fun BufferedReader.readMessage(): Message? =
withContext(Dispatchers.IO) {
readLine()?.parseMessage()
}
заблокируется один из потоков из пула Dispatchers.IO, а вот вызывающий поток нет т.к. будет создана корутина, которая будет suspended до тех пор пока тот поток из Dispatchers.IO не разблокируется. т.е. такой код можно написать: launch { while(true) { println("I'm not blocked ${Thread.currentThread().name}"); delay(200L); } } withContext(Dispatchers.IO) { println("I'm blocked ${Thread.currentThread().name}"); Thread.sleep(1000L); }
Вы, возможно, с обычным вызовом suspend-функции путаете -- там да, до первого suspension point выполнение будет сразу без приостановки. Но withContext имеет шанс переключить диспетчер до вызова переданной в него функции, там всё хорошо.
Но я не совсем понимаю, а как это работает? Launch же ждет, пока delay не вернет ему то, что она suspend и пока не вернет, дальше он не пойдет, а Dispacher.IO каким-то образом сразу выполняет на своем потоке, он же не может просто обернуть всю функцию и сказать "Закинь в мою очередь, я сам это потом выполню". Я посмотрел декомпилированный байткод этого кода и sleep там находится в самом первом стейте, где там возвращается SUSPENDED я не понимаю.
Ну переключил он диспетчер, а что это дало? Диспетчер же будет работать только во время resume, а его никто не вызовет, так как никто и не саспендился. Вероятнее всего, я ошибочно представляют себе работу диспетчера, не подскажете какой-нибудь материал по ним?
а что такое корутины вы понимаете? и Continuation Passing Style механизм. если не совсем, то лучше посмотреть на теорию, там должно быть понятно.
Надо по чату поискать, тут ссылок на ютуб уже накидывали на эту тему
Ну вот я как раз и представляю, что в каждую suspend функцию передается continuation(если он уже есть), пока какая-то из функций не вернет COURUTINE_SUSPEND, после чего мы прокидываемся по call stack'у вверх, а когда асинхронная функция завершится, дернет колбэк, где вызовет resume, который обернут реализацией диспетчера, который, например, закинет джобу куда-нибудь и продолжит выполнять корутины согласно состоянию из continuation.
> только во время resume Вот это не совсем верно, он может перехватить continuation до первой приостановки
А, т.е. диспатчер еще какой-то initialCode запускает, где тупо берет какой-то поток и запускает там эту функцию. Т.е. по сути, это просто обертка над new Thread(...).start(), т.к. suspension point'ов нет, то и стейт-машина будет состоять из одного стейта.
Ну я бы сказал, что CoroutineDispatcher/CoroutineInterceptor может перехватить начало выполнения suspend-кода в контексте, в котором он лежит, ещё до засыпания корутины и последующего resume. Поток может даже не браться из пула, а просто использоваться один единственный или вообще выполнение кода может быть делегировано UI-фреймворку (см. Dispatchers.Main). Это уже не так важно. Важно то, что dispatcher/interceptor контролирует, в каком потоке выполняется код, не только после засыпания корутины.
Угу, понял, спасибо.
Обсуждают сегодня