Правильный способ приостановить сопрограммы, пока задача <T>не будет завершена - PullRequest
0 голосов
/ 13 мая 2018

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

В настоящее время я использую это расширение для приостановки.coroutine

suspend fun <T> awaitTask(task: Task<T>): T = suspendCoroutine { continuation ->
    task.addOnCompleteListener { task ->
        if (task.isSuccessful) {
            continuation.resume(task.result)
        } else {
            continuation.resumeWithException(task.exception!!)
        }
    }
}

Но недавно я видел такое использование

suspend fun <T> awaitTask(task: Task<T>): T = suspendCoroutine { continuation ->
    try {
        val result = Tasks.await(task)
        continuation.resume(result)
    } catch (e: Exception) {
        continuation.resumeWithException(e)
    }
}

Есть ли разница, и какая из них правильная?

UPD: второй пример isnне работает, idk, почему

Ответы [ 2 ]

0 голосов
/ 14 мая 2018

Блок кода, переданный suspendCoroutine { ... }, не должен блокировать поток, в котором он вызывается, что позволяет приостановить сопрограмму.Таким образом, фактический поток может использоваться для других задач.Это ключевая функция, которая позволяет сопрограммам Kotlin масштабировать и запускать несколько сопрограмм даже в одном потоке пользовательского интерфейса.

Первый пример делает это правильно, потому что он вызывает )" rel="noreferrer">task.addOnCompleteListener (см. Документы) (который просто добавляет слушателя и немедленно возвращает его. Вот почему первый работает правильно.

Во втором примере используется )" rel="noreferrer">Tasks.await(task) (см. Документы) , который блоки поток, в котором он вызывается и не возвращается до тех пор, пока задача не будет завершена, поэтому он не позволяет корректно приостановить сопрограмму.

0 голосов
/ 13 мая 2018

Ваш второй пример - более традиционная функция блокировки.

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

Также в типичной Java существует более новая парадигма, называемая Реактивное программирование, которая позволяет избежать блокировки потока до тех пор, пока результат не вернется. Вместо того, чтобы просто ждать результата, вы предоставляете первоклассную функцию, которая будет выполняться при получении результата. Таким образом, на паузе не осталось потока; вместо этого к потоку, выполняющему длинную операцию, добавлено только новое событие, и когда операция завершится, это событие сработает.

Блокировка:

Thread one:  --* . . . ./---
Thread two:     \------*

Реактивный:

Thread one: --*   (now free)
Thread two:    \-------*---

Если вы исследуете Реактивное Программирование, вы найдете гораздо лучшие объяснения, которые идут вглубь.

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

Однако , парадигма по-прежнему имеет свои достоинства, поэтому имеет смысл видеть людей, продолжающих работать по этой схеме, даже если это не так строго необходимо, как в других местах.

...