Как использовать SuspendCoroutine, чтобы превратить будущее Java 7 в функцию приостановки Kotlin - PullRequest
0 голосов
/ 11 июня 2018

Как лучше всего обернуть фьючерсы Java 7 внутри функции приостановки kotlin?Есть ли способ преобразовать метод, возвращающий фьючерсы Java 7, в функцию приостановки?

Процесс довольно прост для произвольных обратных вызовов или завершаемых java 8, как показано, например, здесь: * https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#suspending-functions

В этих случаях есть ловушка, которая срабатывает, когда будущееготово, поэтому его можно использовать для возобновления продолжения, как только будет определено значение будущего (или сработало исключение).

Фьючерсы на Java 7, однако, не предоставляют метод, который вызывается по окончании вычислений.

Преобразование будущего Java 7 в будущее, совместимое с Java 8, не вариант в моей кодовой базе.

Конечно, я могу создать функцию приостановки, которая вызывает future.get (), но это будет блокировка, которая нарушает общую цель использования сопрограммы с приостановкой.

Другой вариант - отправить исполняемый файл новому исполнителю потока, а внутри запускаемого вызова future.get () и вызвать обратный вызов.Эта оболочка заставит код выглядеть «неблокирующим» с точки зрения потребителя, сопрограмма может быть приостановлена, но под капотом мы все еще пишем код блокировки и создаем новый поток только ради его блокировки

Ответы [ 2 ]

0 голосов
/ 20 октября 2018

Конечно, Роман прав, что Java Future не позволяет вам предоставить обратный вызов, когда работа завершена.

Тем не менее, это дает вам возможность проверить, выполнена ли работа,и если это так, то вызов .get() не будет блокировать.

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

Давайте напишем эту логику опроса, а также продадим ее как метод расширения:

suspend fun <T> Future<T>.wait(): T {
    while(!isDone)
        delay(1) // or whatever you want your polling frequency to be
    return get()
}

Затем используем:

fun someBlockingWork(): Future<String> { ... }

suspend fun useWork() {
    val result = someBlockingWork().wait()
    println("Result: $result")
}

Таким образом, у нас есть время отклика в миллисекундах на завершение нашего будущего без использования каких-либодополнительные потоки.


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

suspend fun <T> Future<T>.wait(timeoutMs: Int = 60000): T? {
    val start = System.currentTimeMillis()
    while (!isDone) {
        if (System.currentTimeMillis() - start > timeoutMs)
            return null
        delay(1)
    }
    return get()
}
0 голосов
/ 15 июня 2018

Будущее Java 7 - блокирование .Он не предназначен для асинхронных API и не предоставляет никакого способа установить обратный вызов, который вызывается, когда будущее завершено.Это означает, что нет прямого способа использовать suspendCoroutine с ним, потому что suspendCoroutine предназначен для использования с API-интерфейсами с асинхронным обратным вызовом.

Однако, если ваш код на самом деле работает под JDK 8 или более новой версией, существует высокая вероятность того, что фактический экземпляр Future, который есть в вашем коде, будет реализовывать интерфейс CompletionStage ввремя выполнения.Вы можете попытаться привести его к CompletionStage и использовать готовое расширение CompletionStage.await из kotlinx-coroutines-jdk8 модуля библиотеки kotlinx.coroutines.

...