https://kotlinlang.org logo
Docs
Join the conversationJoin Slack
Channels
100daysofcode
100daysofkotlin
100daysofkotlin-2021
advent-of-code
aem
ai
alexa
algeria
algolialibraries
amsterdam
android
android-architecture
android-databinding
android-studio
androidgithubprojects
androidthings
androidx
androidx-xprocessing
anime
anko
announcements
apollo-kotlin
appintro
arabic
argentina
arkenv
arksemdevteam
armenia
arrow
arrow-contributors
arrow-meta
ass
atlanta
atm17
atrium
austin
australia
austria
awesome-kotlin
ballast
bangladesh
barcelona
bayarea
bazel
beepiz-libraries
belgium
berlin
big-data
books
boston
brazil
brikk
budapest
build
build-tools
bulgaria
bydgoszcz
cambodia
canada
carrat
carrat-dev
carrat-feed
chicago
chile
china
chucker
cincinnati-user-group
cli
clikt
cloudfoundry
cn
cobalt
code-coverage
codeforces
codemash-precompiler
codereview
codingame
codingconventions
coimbatore
collaborations
colombia
colorado
communities
competitive-programming
competitivecoding
compiler
compose
compose-android
compose-desktop
compose-hiring
compose-ios
compose-mp
compose-ui-showcase
compose-wear
compose-web
connect-audit-events
corda
cork
coroutines
couchbase
coursera
croatia
cryptography
cscenter-course-2016
cucumber-bdd
cyprus
czech
dagger
data2viz
databinding
datascience
dckotlin
debugging
decompose
decouple
denmark
deprecated
detekt
detekt-hint
dev-core
dfw
docs-revamped
dokka
domain-driven-design
doodle
dsl
dublin
dutch
eap
eclipse
ecuador
edinburgh
education
effective-kotlin
effectivekotlin
emacs
embedded-kotlin
estatik
event21-community-content
events
exposed
failgood
fb-internal-demo
feed
firebase
flow
fluid-libraries
forkhandles
forum
fosdem
fp-in-kotlin
framework-elide
freenode
french
fritz2
fuchsia
functional
funktionale
gamedev
ge-kotlin
general-advice
georgia
geospatial
german-lang
getting-started
github-workflows-kt
glance
godot-kotlin
google-io
gradle
graphic
graphkool
graphql
graphql-kotlin
graviton-browser
greece
grpc
gsoc
gui
hackathons
hacktoberfest
hamburg
hamkrest
helios
helsinki
hexagon
hibernate
hikari-cp
hire-me
hiring
hongkong
hoplite
http4k
hungary
hyderabad
image-processing
india
indonesia
inkremental
intellij
intellij-plugins
intellij-tricks
internships
introduce-yourself
io
ios
iran
israel
istanbulcoders
italian
jackson-kotlin
jadx
japanese
jasync-sql
java-to-kotlin-refactoring
javadevelopers
javafx
javalin
javascript
jdbi
jhipster-kotlin
jobsworldwide
jpa
jshdq
juul-libraries
jvm-ir-backend-feedback
jxadapter
k2-early-adopters
kaal
kafka
kakao
kalasim
kapt
karachi
karg
karlsruhe
kash_shell
kaskade
kbuild
kdbc
kgen-doc-tools
kgraphql
kinta
klaxon
klock
kloudformation
kmdc
kmm-español
kmongo
knbt
knote
koalaql
koans
kobalt
kobweb
kodein
kodex
kohesive
koin
koin-dev
komapper
kondor-json
kong
kontent
kontributors
korau
korean
korge
korim
korio
korlibs
korte
kotest
kotest-contributors
kotless
kotlick
kotlin-asia
kotlin-beam
kotlin-by-example
kotlin-csv
kotlin-data-storage
kotlin-foundation
kotlin-fuel
kotlin-in-action
kotlin-inject
kotlin-latam
kotlin-logging
kotlin-multiplatform-contest
kotlin-mumbai
kotlin-native
kotlin-pakistan
kotlin-plugin
kotlin-pune
kotlin-roadmap
kotlin-samples
kotlin-sap
kotlin-serbia
kotlin-spark
kotlin-szeged
kotlin-website
kotlinacademy
kotlinbot
kotlinconf
kotlindl
kotlinforbeginners
kotlingforbeginners
kotlinlondon
kotlinmad
kotlinprogrammers
kotlinsu
kotlintest
kotlintest-devs
kotlintlv
kotlinultimatechallenge
kotlinx-datetime
kotlinx-files
kotlinx-html
kotrix
kotson
kovenant
kprompt
kraph
krawler
kroto-plus
ksp
ktcc
ktfmt
ktlint
ktor
ktp
kubed
kug-leads
kug-torino
kvision
kweb
lambdaworld_cadiz
lanark
language-evolution
language-proposals
latvia
leakcanary
leedskotlinusergroup
lets-have-fun
libgdx
libkgd
library-development
linkeddata
lithuania
london
losangeles
lottie
love
lychee
macedonia
machinelearningbawas
madrid
malaysia
mathematics
meetkotlin
memes
meta
metro-detroit
mexico
miami
micronaut
minnesota
minutest
mirror
mockk
moko
moldova
monsterpuzzle
montreal
moonbean
morocco
motionlayout
mpapt
mu
multiplatform
mumbai
munich
mvikotlin
mvrx
myndocs-oauth2-server
naming
navigation-architecture-component
nepal
new-mexico
new-zealand
newname
nigeria
nodejs
norway
npm-publish
nyc
oceania
ohio-kotlin-users
oldenburg
oolong
opensource
orbit-mvi
osgi
otpisani
package-search
pakistan
panamá
pattern-matching
pbandk
pdx
peru
philippines
phoenix
pinoy
pocketgitclient
polish
popkorn
portugal
practical-functional-programming
proguard
prozis-android-backup
pyhsikal
python
python-contributors
quasar
random
re
react
reaktive
realm
realworldkotlin
reductor
reduks
redux
redux-kotlin
refactoring-to-kotlin
reflect
refreshversions
reports
result
rethink
revolver
rhein-main
rocksdb
romania
room
rpi-pico
rsocket
russian
russian_feed
russian-kotlinasfirst
rx
rxjava
san-diego
science
scotland
scrcast
scrimage
script
scripting
seattle
serialization
server
sg-user-group
singapore
skia-wasm-interop-temp
skrape-it
slovak
snake
sofl-user-group
southafrica
spacemacs
spain
spanish
speaking
spek
spin
splitties
spotify-mobius
spring
spring-security
squarelibraries
stackoverflow
stacks
stayhungrystayfoolish
stdlib
stlouis
strife-discord-lib
strikt
students
stuttgart
sudan
swagger-gradle-codegen
swarm
sweden
swing
swiss-user-group
switzerland
talking-kotlin
tallinn
tampa
teamcity
tegal
tempe
tensorflow
terminal
test
testing
testtestest
texas
tgbotapi
thailand
tornadofx
touchlab-tools
training
tricity-kotlin-user-group
trójmiasto
truth
tunisia
turkey
turkiye
twitter-feed
uae
udacityindia
uk
ukrainian
uniflow
unkonf
uruguay
utah
uuid
vancouver
vankotlin
vertx
videos
vienna
vietnam
vim
vkug
vuejs
web-mpp
webassembly
webrtc
wimix_sentry
wwdc
zircon
Powered by Linen
coroutines
  • c

    Choi

    10/22/2022, 6:14 AM
    Internally, I found that the suspend function is suspended when the invokeSuspend function returns a
    COROUTINE_SUSPENDED
    Enum . If so, when exactly does COROUTINE_SUSPENDED return?
    e
    • 2
    • 1
  • r

    reactormonk

    10/22/2022, 7:24 AM
    A default
    Flow
    isn't closable because it's cold?
    s
    e
    i
    • 4
    • 12
  • b

    Brendan Weinstein

    10/23/2022, 11:26 PM
    I am seeing this report in Bugsnag where the root exception is swallowed. Has anyone seen something similar before or have tips on how to best find the true root cause?
    0  libsystem_kernel.dylib  ___pthread_kill
    1  libsystem_pthread.dylib _pthread_kill
    2  libsystem_c.dylib       _abort
    3  BaseBetaiOS             konan::abort() (BaseBetaiOS)
    4  BaseBetaiOS             (anonymous namespace)::terminateWithUnhandledException(ObjHeader*)::$_1::operator()() const (BaseBetaiOS)
    5  BaseBetaiOS             void (anonymous namespace)::$_0::operator()<(anonymous namespace)::terminateWithUnhandledException(ObjHeader*)::$_1>((anonymous namespace)::terminateWithUnhandledException(ObjHeader*)::$_1) (BaseBetaiOS)
    6  BaseBetaiOS             (anonymous namespace)::terminateWithUnhandledException(ObjHeader*) (BaseBetaiOS)
    7  BaseBetaiOS             (anonymous namespace)::processUnhandledException(ObjHeader*) (BaseBetaiOS)
    8  BaseBetaiOS             kfun:kotlinx.coroutines#handleCoroutineException(kotlin.coroutines.CoroutineContext;kotlin.Throwable){} (BaseBetaiOS)
    9  BaseBetaiOS             kfun:kotlinx.coroutines.StandaloneCoroutine.handleJobException#internal (BaseBetaiOS)
    10 BaseBetaiOS             kfun:kotlinx.coroutines.JobSupport.finalizeFinishingState#internal (BaseBetaiOS)
    11 BaseBetaiOS             kfun:kotlinx.coroutines.JobSupport.tryMakeCompleting#internal (BaseBetaiOS)
    12 BaseBetaiOS             kfun:kotlinx.coroutines.JobSupport#makeCompletingOnce(kotlin.Any?){}kotlin.Any? (BaseBetaiOS)
    13 BaseBetaiOS             kfun:kotlinx.coroutines.AbstractCoroutine#resumeWith(kotlin.Result<1:0>){} (BaseBetaiOS)
    14 BaseBetaiOS             kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#resumeWith(kotlin.Result<kotlin.Any?>){} (BaseBetaiOS)
    15 BaseBetaiOS             kfun:kotlinx.coroutines.DispatchedTask#run(){} (BaseBetaiOS)
    16 BaseBetaiOS             kfun:kotlinx.coroutines.DarwinGlobalQueueDispatcher.$dispatch$lambda$0$FUNCTION_REFERENCE$693.$<bridge-UNN>invoke(){}#internal (BaseBetaiOS)
    17 BaseBetaiOS             ___6f72672e6a6574627261696e732e6b6f746c696e783a6b6f746c696e782d636f726f7574696e65732d636f7265_knbridge762_block_invoke (BaseBetaiOS)
    18 libdispatch.dylib       __dispatch_call_block_and_release
    19 libdispatch.dylib       __dispatch_client_callout
    20 libdispatch.dylib       __dispatch_root_queue_drain
    21 libdispatch.dylib       __dispatch_worker_thread2
    22 libsystem_pthread.dylib __pthread_wqthread
    r
    • 2
    • 3
  • r

    Ruben Quadros

    10/24/2022, 7:17 AM
    I have the following use case: My function returns a flow.. for simplicity lets say it returns
    Flow<Int>
    In this function I have an api call which also returns a flow What is the best way to give result back to the caller? Sample code in thread
    j
    • 2
    • 4
  • z

    zalewski.se

    10/24/2022, 5:23 PM
    Hi everyone 👋 Considering the project setup where you would have implicit dependencies with particular version of kotlinx coroutines enforced, how safe would that be in case of 3rd party dependencies? Would it impose any risk when a library has been compiled with one version of coroutines core but using newer version in the runtime? In case of most API breaking changes it’s quite easy as it will fail during compilation phase but I wonder how safe would it be to assume that breaking changes within core would always come with some new API 🤔
    l
    • 2
    • 2
  • t

    Tim Malseed

    10/26/2022, 12:26 AM
    I have a question around testing.. If I have a MutableStateFlow, and a function which updates that StateFlow multiple times, is there a way to test that the StateFlow went through the expected intermediate states?
    j
    j
    • 3
    • 8
  • j

    João Gabriel Zó

    10/26/2022, 1:26 PM
    does
    withContext()
    get it’s own coroutineScope or inherit it from whoever is calling the function?
    m
    s
    • 3
    • 2
  • v

    Vaibhav Nalawade

    10/26/2022, 4:37 PM
    How excute in order I want execution in order[FIFO] how i can archive that
    scope.launch{
    List.forEach{
      Something(it)
    }
    s
    • 2
    • 1
  • c

    CLOVIS

    10/26/2022, 7:20 PM
    In new code that doesn't use flows, is there a recommendation/preference between
    coroutineContext
    and
    currentCoroutineContext()
    ?
    l
    • 2
    • 3
  • s

    SecretX

    10/27/2022, 11:31 AM
    Morning! I would like to know how I could, when spring boot is shutting down, await for a CoroutineScope childrens to end, more especifically I would like to "close" a CoroutineScope without cancelling its childrens, that is, prevent new jobs from being posted and throw if an attempt is make, and then await for its childrens to finish their work, and only then finish the application. This is not specific for Spring Boot, I only need to figure out how to close a Coroutine Scope without cancelling its children, how could I do this?
    s
    s
    • 3
    • 2
  • r

    Rajar

    10/31/2022, 11:09 AM
    Hello! Does anyone know how to ensure that a suspend lambda parameter is really
    suspend
    and not a non-suspend one ? If possible it could be an annotation where the ensuring would happen. My use case is:
    suspend fun <T> execute(request: suspend () -> T): T {
      // code here
    }
    
    ...
    //code using 'execute'
    execute(mySuspendLambda) // OK
    execute { 1+1 } // warning or error
    j
    s
    k
    • 4
    • 24
  • d

    dawidhyzy

    10/31/2022, 2:06 PM
    I tried to search for it but with no luck. How to combine more than 5 flows?
    k
    l
    l
    • 4
    • 7
  • d

    Dragan Vojvodić

    10/31/2022, 3:09 PM
    Hi everyone, I have a question regarding Flow collection inside Fragment. My app heavily depends on Flow, and I have a lot of places where I need to collect it in UI layer, so I wanted to create an extension function to reduce the boilerplate code I need to write every time I have to collect it...
    inline fun <T> Fragment.collectFlowSafely(
        flowToCollect: Flow<T>,
        repeatState: Lifecycle.State = Lifecycle.State.STARTED,
        crossinline value: (T) -> Unit
    ) {
        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(repeatState) {
                flowToCollect.collect {
                    value(it)
                }
            }
        }
    }
    Would this way of collecting flow be safe from cancellation point of view? i.e. Would cancel the collection when the view is no longer visible etc?
  • s

    Sushobh

    11/01/2022, 2:18 AM
    Hi Team, I understand that runBlocking waits for coroutines launched from its scope to wait. However when I create a new scope using runBlocking scope's coroutine context, runBlocking will wait for the coroutines launched from this new scope. My question is what parameter of coroutine context does runBlocking use to decide if it wants to wait for a launched coroutine. If you have any resources for the inner workings of runBlocking please provide them. Thanks.
    s
    g
    • 3
    • 8
  • k

    K Merle

    11/01/2022, 7:20 AM
    How do I wait for
    flow
    for specific amount of time, and collect all, or return null?
    e
    • 2
    • 2
  • h

    hfhbd

    11/02/2022, 9:07 AM
    How can you debug the origin (in the code) of a started coroutine on Kotlin/Native? I want to cancel a job but the cancelation does not finish and I am unable to find the cause.
    g
    • 2
    • 2
  • j

    janvladimirmostert

    11/02/2022, 10:20 AM
    are there any plans in the future to allow overloading methods based on whether they're suspending or not?
    fun blah() { ... }
    
    suspend fun blah() { ... }
    now if I'm in a coroutineContext and call blah, it calls the suspending one and if I'm not in a coroutineContext or in Java-land, it calls the non-suspending one
    s
    g
    • 3
    • 4
  • s

    Sam

    11/02/2022, 1:21 PM
    Why is
    launch
    allowed to cancel itself but
    coroutineScope
    isn’t?
    k
    • 2
    • 22
  • r

    rocketraman

    11/03/2022, 6:23 PM
    On upgrading a multi-platform (JVM, JS with IR) project to Kotlin 1.7.10 and coroutines 1.6.4, I now get this error at build time:
    > Task :shared:kspKotlinFrontend FAILED
    e: Could not find "org.jetbrains.kotlin:kotlinx-atomicfu-runtime" in [/home/raman/.local/share/kotlin/daemon]
    e: java.lang.IllegalStateException: FATAL ERROR: Could not find "org.jetbrains.kotlin:kotlinx-atomicfu-runtime" in [/home/raman/.local/share/kotlin/daemon]
            at org.jetbrains.kotlin.ir.backend.js.KlibKt$toResolverLogger$1.fatal(klib.kt:106)
    This issue exists, but is marked as resolved: https://github.com/Kotlin/kotlinx.coroutines/issues/3305. I don't depend on atomicfu directly -- only indirect dependencies via coroutines.
    i
    • 2
    • 5
  • a

    Augusto

    11/05/2022, 11:02 AM
    Hi All! I'm looking at the coroutines code to understand a bit more what is going under the hood and I found this in
    delay()
    public suspend fun delay(timeMillis: Long) {
        if (timeMillis <= 0) return // don't delay
        return suspendCancellableCoroutine sc@ { cont: CancellableContinuation<Unit> ->
            //some extra code
        }
    }
    I wonder if there's a reason to do
    return suspendCancellableCoroutine[...]
    rather than just calling
    suspendCancellableCoroutine()
    , as
    delay()
    returns
    Unit
    .
    z
    e
    • 3
    • 5
  • a

    Alex Styl

    11/07/2022, 8:29 AM
    How come this
    error()
    doesn’t crash the app? Given there is no supervisor job I was expecting this to crash the program but it doesn’t. I can see the ‘Starting’ the crash and then ‘job done’ in the logs 🤔
    suspend fun main() {
        val scope = CoroutineScope(Dispatchers.Main.immediate)
        debugLn { "Starting" }
        scope.launch {
            error("CRASH!")
        }
        delay(500)
        debugLn { "Job done" }
    }
    s
    s
    • 3
    • 3
  • o

    oday

    11/07/2022, 9:07 AM
    so i have this code that fetches data, typical usecases that fetch data from an API upon starting a viewmodel
    var location = mutableStateOf<GetLocation.Location?>(null)
    var dateRange = mutableStateOf<DateRange?>(null)
    var category = mutableStateOf(Category.All)
    var period = mutableStateOf(Period.Any)
    
    fun fetchData() {
        viewModelScope.launch(<http://dispatchers.io|dispatchers.io>) {
            getLocation.execute().fold(
                onSuccess = { response ->
                    withContext(dispatchers.main) {
                        location.value = response.orNull()
                    }
                },
                onFailure = {
                    logger.log(it)
                }
            )
    .... etc....
    but I would like to observe any changes in these fields and fetch again when they’ve been updated is there like a combineLatest?
    • 1
    • 2
  • l

    Lukas Lechner

    11/07/2022, 10:17 AM
    Is there a common use case for using channels for Android Development? I am only aware of using them for Single UI Events; however, Google recommends not using them for this purpose.
    b
    j
    +2
    • 5
    • 9
  • w

    Wai-Wai Ng

    11/07/2022, 5:02 PM
    Conceptual question: I have a bunch of coroutines that might at some point want to know, say, the latest USD-EUR conversion rate. My
    getUsdEurRate()
    function is expensive, so essentially what I want is: • Every consumer registers somewhere • When there is an active registration, the function gets kicked off and all the consumers suspend until we get a value back ◦ As other consumers may register while the function is running • No consumer should ever get a stale value My first approach was to use a 0-capacity synchronization channel, but based on the above thread, it sounds like channels don't really support both "no buffered values" and "multiple consumers get the same value". Is a flow the right approach here? Or something else?
    j
    k
    +4
    • 7
    • 9
  • a

    Alexander

    11/08/2022, 11:39 AM
    I'm trying to debug coroutines using a javaagent form a
    kotlinx-coroutines-debug
    library. After sending a
    SIGTRAP
    signal there are coroutines stacktraces like following:
    Coroutine StandaloneCoroutine{Active}@4491c16c, state: SUSPENDED
            ...
    
    Coroutine StandaloneCoroutine{Active}@27559007, state: SUSPENDED
            ...
    However it is not possible to understand which stack belongs to which coroutine. All my coroutines have unique names. Is it possible to activate printing coroutine names?
    r
    • 2
    • 5
  • j

    Joel Steres

    11/11/2022, 6:01 PM
    Hi. I have a long running flow (compose 1.2.1), which has several flatMapLatest calls on other observables. When the user logs out an observable near the top of the flow emits. I am having trouble seeing how to interrupt the downstream observables, which are seeing the missing data after logout and attempting to request updates. One of the ideas I tried was
    observeLoginState().map { it is LoggedIn }
    .distinctUntilChanged()
    .flatMapLatest { isLoggedIn ->
        if (isLoggedIn) { dataSource.observe() }
        else { emptyFlow() }
    }
    ...
    .flatMap {}
    ,,,
    ,launchedIn(scope)
    However it really seems like the downstream flatMaps are continuing to observe even when a flatMapLatest upstream has changed. Am I doing something wrong? Is there a way to cancel the downstream observers while keeping the flow alive? A couple of other ideas I tried: • Threading a null or sentinel value through the flow so downstream observers could be swapped out but requires too many compromises about the type of data based along the flow. • throwing an exception and using retryWhen to restart the flow. I ran into an exception retry loop when logged out which I should have seen even before I tried. Even though I expect it could be made workable, I didn’t really spend the time looking further as it felt kludgey.
    b
    • 2
    • 2
  • s

    Slackbot

    11/11/2022, 7:00 PM
    This message was deleted.
    i
    t
    • 3
    • 4
  • d

    Daniele Segato

    11/12/2022, 5:40 PM
    Is there an idiomatic way to create a dynamic Proxy in Kotlin? I've been trying with
    java.reflect.Proxy
    with awful results This proxy job is to intercept, detect if a particular exception is throw and if so unwrap it and throw the underlying exception. This has to work with suspend functions
    class UnwrapExceptionProxy<T>(private val instance: T): InvocationHandler {
        @Suppress("UNCHECKED_CAST")
        override fun invoke(proxy: Any, method: Method, args: Array<out Any?>?): Any? {
            val function = method.kotlinFunction!!
    
            return if (function.isSuspend) {
                val parameters = Array(args!!.size - 1) {args[it] }
                val continuation = args.last() as Continuation<Any?>
                method.invoke(instance, *parameters, Continuation<Any?>(continuation.context) { result ->
                    val wrappedError = result.exceptionOrNull() as? MyWrapException
                    if (wrappedError == null) {
                        continuation.resumeWith(result)
                    } else {
                        continuation.resumeWith(Result.failure(wrappedError.wrapped))
                    }
                })
            } else {
                val parameters = args ?: arrayOf()
                try {
                    method.invoke(instance, *parameters)
                } catch (e: MyWrapException) {
                    throw e.wrapped
                }
            }
        }
    }
    1. First, I'm not sure if I've handled the suspend function correctly 2. I get
    java.lang.reflect.UndeclaredThrowableException
    every time my kotlin code throws a non
    RuntimeException
    Is there no way to write a Proxy for kotlin? I cannot force declaring all checked exceptions and I wanted to make this as transparent as possible.
    j
    e
    • 3
    • 20
  • e

    Exerosis

    11/14/2022, 8:27 AM
    How can I avoid the ClosedByInterruptException from being throw up when doing something like this:
    val test = withTimeoutOrNull(3.seconds) {
        runInterruptible {
            channel.receive(ByteBuffer.allocateDirect(10))
        }
    }
    I would have expected null to be returned. Catching the exception results in a value being returned instead of null.
    j
    s
    u
    • 4
    • 6
  • j

    James Eschner

    11/14/2022, 4:09 PM
    Hello, I am somewhat new to coroutines and running into an issue I don’t understand using
    CoroutineStart.LAZY
    . It appears, that if I don’t cancel or await a response, the
    runBlocking
    section never properly terminates. Any ideas?
    fun main() = runBlocking {
        val lazyDeferredInt: Deferred<Int> = async(start = CoroutineStart.LAZY) {
            5
        }
    }
    
    main()
    
    println("##### [scratch] done")
    that print statement never executes 😢
    fun main() = runBlocking {
        val lazyDeferredInt: Deferred<Int> = async(start = CoroutineStart.LAZY) {
            5
        }
    
        lazyDeferredInt.await()
    }
    
    main()
    
    println("##### [scratch] done")
    now I see
    "##### [scratch] done"
    printed * Not a contribution *
    p
    g
    • 3
    • 11
Powered by Linen
Title
j

James Eschner

11/14/2022, 4:09 PM
Hello, I am somewhat new to coroutines and running into an issue I don’t understand using
CoroutineStart.LAZY
. It appears, that if I don’t cancel or await a response, the
runBlocking
section never properly terminates. Any ideas?
fun main() = runBlocking {
    val lazyDeferredInt: Deferred<Int> = async(start = CoroutineStart.LAZY) {
        5
    }
}

main()

println("##### [scratch] done")
that print statement never executes 😢
fun main() = runBlocking {
    val lazyDeferredInt: Deferred<Int> = async(start = CoroutineStart.LAZY) {
        5
    }

    lazyDeferredInt.await()
}

main()

println("##### [scratch] done")
now I see
"##### [scratch] done"
printed * Not a contribution *
p

phldavies

11/14/2022, 4:13 PM
By defining the deferred as
LAZY
you’re explicitly telling it to not start until required. As such, unless explicitly started or awaited it will not run. The outer
runBlocking
scope will only complete once all child coroutines have completed, which is why you’re not seeing the last println (it’s still waiting for the unstarted async call to complete)
j

James Eschner

11/14/2022, 4:14 PM
Aha! That’s the piece I needed, makes sense, thank you very much.
p

phldavies

11/14/2022, 4:20 PM
you can always
.cancel()
the deferred if you want to avoid it running in some circumstances
.isActive
will return false if the deferred is either non-started or has finished (or cancelled) - either way, cancelling it in that state should be safe
j

James Eschner

11/14/2022, 4:26 PM
Right, yes I explored that and might be what I go with. Right now I’m working with a flow that looks something like this:
fun main() = runBlocking {
  // expensive operations that don't necessarily need to run
  val a: Deferred<T> = async(start = CoroutineStart.LAZY) { ... }
  val b: Deferred<T> = async(start = CoroutineStart.LAZY) { ... }
  val c: Deferred<T> = async(start = CoroutineStart.LAZY) { ... }

  if (<some condition>) {
    a.await()
    b.await()
    c.await()
    // run some logic
  }

  if (<some other condition) {
    a.await()
    // run some other logic
  }

  a.cancel()
  b.cancel()
  c.cancel()
}
But perhaps there is a better way to design this ** Not a contribution
p

phldavies

11/14/2022, 4:54 PM
you’re better off using
.start
at the beginning of each block so that they’re executed concurrently. Possibly using a helper such as
fun startAll(varargs jobs: Job) = jobs.forEach(Job::start)
. You can also use a helper
async
wrapper such as
val deferreds = mutableListOf<Deferred<*>>()
fun <T> lazyAsync(block: suspend CoroutineScope.() -> T) 
    = async(start = CoroutineStart.LAZY, block = block).also(deferreds::add)

val a = lazyAsync { ... }
val b = lazyAsync { ... }
val c = lazyAsync { ... }

if (<some condition>) {
  startAll(a, b, c)
  // logic using a.await() etc where value needed
}

// etc

deferreds.forEach(Job::cancel)
g

gildor

11/15/2022, 2:48 AM
Making those coroutines lazy kills parallel execution completely in your case, a, b, c will always run sequentially because of lazy (b is not started until a is finished etc) Personally instead of doing it with lazy, I would just extract starting block of
a, b, c
to own function and
a
to one more function, so it would be easy to read and it would run in paralel
also declaring those as suspend functions will make it a lot more safe (no way someone forget to cancel some future
d
and get hanging code because of this
so essentially directly translating your example I would just do:
fun main() = runBlocking {
    if (< some condition >) {
        doABC()
        // run some logic
    }

    if (< some other condition >) {
        doA()
        // run some other logic
    }
}

suspend fun doABC() = coroutineScope {
    // Run all operations in paralel
    listOf(
        async { doA() },
        async { doB() },
        async { doC() }
    ).awaitAll()
}

suspend fun doA() {}
suspend fun doB() {}
suspend fun doC() {}
Ah, I actually see why you may need A, you essentially don’t want to restart it, which is a fair use case. I would probably on practice reshuffle code a bit to avoid this semantics, but even without this with a bit of additional logic it can be instead implemented like:
fun main() = runBlocking {
    val aDeferred = async { doA() }
    if ( < some condition >) {
        doABC(aDeferred)
        // run some logic
    }

    if ( < some other condition) {
        aDeferred.await()
        // run some other logic
    }
}

suspend fun doABC(aDeferred: Deferred<Foo>) = coroutineScope {
    listOf(
        aDeferred,
        async { doB() },
        async { doB() }
    ).awaitAll()
}

suspend fun doA() {}
suspend fun doB() {}
suspend fun doC() {}
Not super elegant, but better version would require more information about you actual use case
View count: 6