#kotlin #kotlin-coroutines
#kotlin #kotlin-сопрограммы
Вопрос:
Это некоторый тестовый код, который я использую для изучения сопрограмм kotlin. Код работает как ожидалось и для вывода суммы требуется около 1 секунды, но теперь, если я заменю delay (1000) блокирующим вызовом, таким как сетевой запрос, то коду потребуется около 10 секунд для вывода суммы (каждый вызов занимает около 1 секунды), но если я оберну сетевой вызов в withContext и использую диспетчер ввода-вывода, для вывода суммы потребуется 1 секунда, потому что он выполняется в другом потоке. Использует ли функция задержки какой-то диспетчер для разблокировки потока?
suspend fun asyncDoubleFn(num: Int): Int {
delay(1000)
return num * 2
}
fun main() = runBlocking {
launch {
val tt = measureTimeMillis {
val results = mutableListOf<Deferred<Int>>()
for (num in 0..10) {
val result = async { asyncDoubleFn(num 1) }
results.add(result)
}
val sum = results.map { it.await() }.reduce { acc, i -> acc i }
println("[SUM]: $sum")
}
println("[TT]: $tt")
}
launch {
println("Another coroutine")
}
println("Main Code")
}
Комментарии:
1. Источник: github.com/Kotlin/kotlinx.coroutines/blob/master/common/…
2. Спасибо! Я искал небольшое подробное объяснение, поскольку я новичок в этой концепции, но знаком с JS async await (в основном использую интерфейс JS). В основном я хочу понять, можем ли мы использовать блокирующий API, такой как java.net . URL и запустите его в режиме приостановки.
3. Вы можете взглянуть на
suspendCoroutine
. Я недостаточно знаком с деталями, чтобы полностью объяснить, как это работает, но на KotlinConf был хороший разговор об этом .
Ответ №1:
Использует ли функция delay какой-либо диспетчер для разблокировки потока?
Не только delay
. Все приостанавливаемые функции взаимодействуют с диспетчером.
Вопрос, который вы должны задать: «Какой диспетчер здесь главный?»
И ответ таков: runBlocking
устанавливает свой собственный диспетчер, который отправляет данные потоку, в котором он вызывается. Оба launch
и async
в вашем коде наследуют это.
Имея это в виду:
Если я заменю delay (1000) блокирующим вызовом, таким как сетевой запрос, то коду потребуется около 10 секунд, чтобы вывести сумму (каждый вызов занимает около 1 секунды)
Каждый блокирующий вызов будет привязан к одному потоку диспетчера. Он не сможет выполнять какую-либо другую работу, будучи заблокированным.
но если я оберну сетевой вызов в
withContext
и используюIO
диспетчер, для вывода суммы потребуется 1 секунда, потому что она выполняется в другом потоке
Да, это меняет диспетчера, проблема решена.
Итак, что delay
делает? Это приостанавливает текущую сопрограмму (ту, которая async
была запущена) и возвращает управление диспетчеру, который теперь может возобновить ваш цикл и запустить следующую сопрограмму.
Комментарии:
1. Спасибо за подробный ответ, это устраняет большую часть моего замешательства, вы сказали, что delay приостанавливает текущую сопрограмму и возвращает управление диспетчеру, использует ли delay какое-то планирование очереди задач для запуска кода по истечении времени задержки, работает ли это как setTimeout в JS?.
2. Это работает практически точно так.
runBlocking
Диспетчер устанавливает очередь событий и цикл событий, который разряжает очередь и обрабатывает события. Точно так же, как Android looper, цикл событий Swing или цикл событий JS.