COROUTINE_SUSPENDED и suspendCoroutineOrReturn в Котлине

Идея сопрограммы в котлине заключалась в том, чтобы отвлечь понятие подвески и обратных вызовов и написать простой последовательный код. Вам не нужно беспокоиться о том, приостановлена ​​ли сопрограмма или нет, подобно потокам.

Какова цель suspendCoroutineOrReturn и COROUTINE_SUSPENDED и в каком случае вы могли бы использовать их?

    suspendCoroutineOrReturn и COROUTINE_SUSPENDED были введены совсем недавно в 1.1 для решения конкретной проблемы переполнения стека. Вот пример:

     fun problem() = async { repeat(10_000) { await(work()) } } 

    Где await просто ждет завершения:

     suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Unit { f.whenComplete { value, exception -> // <- await$lambda if (exception != null) c.resumeWithException(exception) else c.resume(value) } } 

    Давайте посмотрим на случай, когда work не приостановлена, но сразу же возвращает результат (например, кэшируется). problem$stateMachine автомат, на котором компилируются сопрограммы в Котлин, собирается сделать следующие вызовы: problem$stateMachine , problem$stateMachine , CompletableFuture.whenComplete , await$lambda , ContinuationImpl.resume , problem$stateMachine , await , …

    По сути, ничто никогда не приостанавливается, и государственный автомат снова и снова запускает себя в том же потоке выполнения, который заканчивается StackOverflowError .

    Предлагаемое решение состоит в том, чтобы разрешить await возврата специального токена ( COROUTINE_SUSPENDED ), чтобы отличить, действительно ли приостановлена ​​или нет COROUTINE_SUSPENDED , так что COROUTINE_SUSPENDED автомат мог избежать переполнения стека. Затем, suspendCoroutineOrReturn для контроля выполнения coroutine. Вот его заявление:

     public inline suspend fun <T> suspendCoroutineOrReturn(crossinline block: (Continuation<T>) -> Any?): T 

    Обратите внимание, что он получает блок, который снабжен продолжением. В принципе, это способ доступа к экземпляру Continuation , который обычно скрывается и появляется только во время компиляции. COROUTINE_SUSPENDED также разрешено возвращать любое значение или COROUTINE_SUSPENDED .

    Поскольку это все выглядит довольно сложно, Котлин пытается скрыть его и рекомендует использовать только функцию suspendCoroutine , которая внутренне делает все, что упомянуто выше для вас. Вот правильная реализация await которая позволяет избежать StackOverflowError (сторона примечание: await отправлено в Kotlin lib, и это фактически функция расширения, но это не так важно для этого обсуждения)

     suspend fun <T> await(f: CompletableFuture<T>): T = suspendCoroutine { c -> f.whenComplete { value, exception -> if (exception != null) c.resumeWithException(exception) else c.resume(value) } } 

    Но если вы когда-либо захотите взять на себя мелкий контроль над продолжением сопрограммы, вы должны вызвать suspendCoroutineOrReturn и вернуть COROUTINE_SUSPENDED всякий раз, когда выполняется внешний вызов.

    Intereting Posts
    Использование Mockito doAnswer в Котлине В Котлине можно изменить делегирование в Runtime? Соответствие регулярных выражений в Котлине Расширения Android Kotlin и сохранившийся фрагмент Как читать текстовый файл из ресурсов в Котлин? Разница между открытыми и переопределяющими методами в Котлине? Поддерживает ли kotlin создание класса, реализующего интерфейс за пределами его файла определения? Запись функции использования Kotlin, которая обеспечивает самооценку в инициализаторе UnsupportedOperationException Команда «android» больше не включена в SDK Поиск с помощью RxJava не работает Несоответствие типа Котлина при прохождении в параметре Как отправить / прикрепить несколько изображений Android – как реализовать несколько ViewHolder для макета заголовка другого для макета модели в адаптере Firestore RecyclerView Android заполняет массив с помощью данных firebase, а не строк вызов API AsyncTask