Комментарии 36
Observable.zip(observable1, observable2, observable3,
(t1, t2, t3) -> new Result(t1, t2, t3))
.subscribe(r -> /* handle result */, () -> /*handle completion*/, e -> /* handle errors */)
try {
val firstChunkJob = async { call1 }
val secondChunkJob = async { call2 }
val thirdChunkJob = async { call3 }
val first = firstChunkJob.await()
sideEffect1(first)
val second = secondChunkJob.await()
sideEffect2(second)
val third = thirdChunkJob.await()
return Result(first, second, third)
} catch (e: Exception) {
// handle errors
}
Пять копеек к слову о Lifecycle Management: в JetBrains рекомендуют реализовывать интерфейс CoroutineScope и переопределять coroutine context.
Самый простой пример с официального сайта kotlinlang.org/docs/reference/coroutines/coroutine-context-and-dispatchers.html#cancellation-via-explicit-job:
class Activity : CoroutineScope {
lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Default + job
fun create() {
job = Job()
}
fun destroy() {
job.cancel()
}
В последнем релизе они захотели привести всё в порядок, поэтому мы не можем вызывать coroutine builders вроде launch() вне coroutine scope.
Для реализации lifecycle-aware jobs предлагается использовать GlobalScope
В ней есть метод
void foo(Runnable r);
suspend fun LibClazz.wrap() = suspendCancellableCoroutine<Unit> { continuation ->
this.foo{
continuation.resume(Unit)
}
}
При это если в пуле потоков для корутин закончатся потоки то вызов будет блокирующим?
Т.е. такой код убивает идею о том что можно запускать сколько угодно корутин потому что они дешевые.
"Внутри" — это где? Внутри вашей любимой библиотеки, конечно же, нет никаких корутин — но не потому что она ими "не может пользоваться", а потому что если бы у нее были корутины, то у нее был бы другой интерфейс.
При это если в пуле потоков для корутин закончатся потоки то вызов будет блокирующим?
Откуда взялся пул потоков для корутин? Приведенный вам пример кода не использует никаких дополнительных потоков.
Откуда взялся пул потоков для корутин?
Ну корутины же выполняются на каких-то потоках? Я не знаю точно как та все устроено, просто предположил что есть некий пул. Или они все в одном потоке работают?
Мой основной вопрос вот в чем: вызов suspendCancellableCoroutine блокирующий?
Что будет с остальными корутинами в этот момент? Они заблокируются до окончания работы этого метода?
Внутри тела метода run выполняется продолжение корутины, о чем можно догадаться по вызову continuation.resume(Unit)
. Конечно же внутри корутины можно пользоваться всеми бонусами корутин!
Вызов suspendCancellableCoroutine
, как можно догадаться из названия, приостанавливает корутину. Приостановленная корутина не выполняется ни в каком потоке.
Остальные корутины тут ни при чем, suspendCancellableCoroutine
влияет только на одну корутину.
pause(10000)
(не помню точно как называется метод) и это освободит текущий поток и он сможет выполнять другую корутину? Звучит здорово. Интересно как они этого добились. Надо по изучать.Как они умудряются копировать стек и работает ли это с нативными методами.
Как они это сделали — документация не раскрывает, но подозреваю что все это сделано точно так же как во всех остальных языках сделан async/await, только синтаксис другой. Копирования стека при таком подходе не требуется.
В общем игрушка крутая, но в таком виде очень ограниченная.
Любая либа которая использует блокирующие вызовы (а это значит все кто лезут в базу или отправляют/принимают запросы по сети или просто используют синхронизацию) просто заблокирует поток и корутины ни как не помогут.
Используйте асинхронные библиотеки вместо синхронных. Их уже достаточно наплодили, что-нибудь да найдёте.
fun main(args: Array<String>) {
GlobalScope.launch {
delay(1000L)
suspendCancellableCoroutine<Unit> { continuation ->
CoolLibrary.doStuff {
delay(1000L)
println("World!") // print after delay
continuation.resume(Unit)
}
}
}
println("Hello,")
Thread.sleep(2000L)
}
Ругается delay внутри doStuff:
Error:(11, 17) Kotlin: Suspension functions can be called only within coroutine body
EDIT
Из вашего комента понял что и не должно
Третий раз вам говорю: все что делается в методе run — возобновляется корутина! Вызовы delay и println надо размещать уже в корутине.
И понятно что я выберу потому что «а кота этого я в первый раз вижу».
Тут обсуждается решение только для первого случая.
Но я не мог этого сделать, потому что не знал всех ограничений которые к этому коду прилагаются (точнее я не был на сто процентов уверен что их не побороли).
А так-же хотел чтобы приверженцы корутин сами признали их ограниченность.
map.forEach { _ ,u -> u.cancel() }
хотел отметить, что в данном случае используется явовый forEach, доступный только в Java 8 (Android 5+). Чтобы заюзать именно котлиновый forEach для мапы, нужно обернуть параметры в скобки:
map.forEach { (_ ,u) -> u.cancel() }
Это выглядит как деструктурирование, и им и является.
RxJava слишком сложный инструмент
…
Я просидел день, но не смог отрефакторить код, чтобы решить задачу.
ок
Как использовать корутины в проде и спокойно спать по ночам