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
  • a

    AdalPari

    12/10/2020, 6:59 PM
    Hi, I'm new to coroutines and I would appreciate some clarification. I'm following different examples of basic coroutines and I'm seeing these two ways of structuring the code. What are the differences, pros and cons of them? Suspend funs to call:
    suspend fun foo1() // function
    suspend fun foo2() // function
    First approach:
    // sequential code
    
    viewModelScope.launch { foo1() }
    
    // more sequential code
    
    viewModelScope.launch { foo2() }
    
    // more sequential code}
    Second approach:
    viewModelScope.launch {
    	// sequential code
    
    	foo1()
    
    	// more sequential code
    
    	foo2()
    
    	// more sequential code
    }
    I've also saw this second approach with
    async
    calls inside the main
    launch
    one. Thanks!
    b
    t
    • 3
    • 7
  • a

    Animesh Sahu

    12/11/2020, 4:54 AM
    Is this a bug, tried invalidating caches still the same. Using
    org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2-native-mt
    problem started yesterday... (Project builds fine)
    l
    • 2
    • 6
  • r

    Ryu Ishikawa

    12/11/2020, 6:55 AM
    Hi folks, now I'm diving into kotlin.coroutines to understand how Coroutines work internally. and I found
    suspendCoroutineUninterceptedOrReturn
    function. It looks like the lowest API I can reach. (since it says
    throw NotImplementedError("Implementation of suspendCoroutineUninterceptedOrReturn is intrinsic")
    ) Is there any good document to understand how it works in bytecode level or anything else? Especially, I'd like to understand how
    suspendCoroutineUninterceptedOrReturn
    capture the current running coroutine. thanks you! (If it's not good to post that here, please let me know where to post 🙇 )
    a
    o
    • 3
    • 3
  • d

    Dariusz Kuc

    12/11/2020, 4:45 PM
    Hello 👋 I was just wondering what is the idiomatic way to launch some side effects from main coroutine whose return value doesn’t depend on it (i.e. side effect can take some time to complete and it is fine if that computation fail) so that it actually does not have to wait for its completion, e.g. given something simple like below
    suspend fun doWork() = coroutineScope {
      val result = ...
      // do some other processing that calculates/processes result
    
      publishData(result) // optional stuff that may be slow, e.g. publish analytics, debug info, etc
      result
    }
    Thanks to structured concurrency if I launch another coroutine from the
    doWork
    , all the child coroutines (including
    publishData
    from above) have to complete before returning from the scope. I could obviously just do
    GlobalScope.launch { publishData }
    but that seems “wrong”. Wondering whether instead I should be using something like buffered
    Channel
    so publish is async and data is processed in another coroutine. Or maybe there is something simpler?
    z
    • 2
    • 5
  • b

    bitkid

    12/11/2020, 7:55 PM
    hi! how can i create a flow where the emitting part runs in a different thread / coroutine context ? assume i have an class which has a method getRemoteService() : Flow<Result>. when calling that method i want the method to immediately start consuming the web service so when i call flow.collect{} it is either already finished or still in the process of fetching. somehow with the flow builders i haven't found a way to do that. should i use in that case a channel directly?
    g
    z
    • 3
    • 5
  • a

    Azur Haljeta

    12/11/2020, 8:18 PM
    They say that coroutine cancellation is cooperative. That's perfect when it's possible to check for it via
    isActive
    . But how to make it cooperative when you're dealing with code which doesn't include loops, i.e. when you don't have a right place to put the
    isActive
    check?
    z
    j
    • 3
    • 22
  • l

    Lilly

    12/11/2020, 9:01 PM
    Hi can someone explain me why consuming the channel suspends forever?
    private val packetChannel: Channel<ResponsePacket> = Channel(Channel.UNLIMITED)
    
        suspend fun sendPacketWithBatchResponse(packet: RequestPacket): List<ResponsePacket> {
            sendPacketWithAcknowledgement(packet)
            val packets = mutableListOf<ResponsePacket>()
    
            for (item in packetChannel) {
                Timber.e("here")
                packets.add(item)
            }
    
            // Unreached code
            return packets
        }
    
        // Another non-suspending function which is decoupled from the consuming function
        fun produce() {
            ...
            packetChannel.offer(packet)
        }
    The goal is to offer multiple packets (~20) to the channel and when finished jump to the
    sendPacketWithBatchResponse
    and consume these packets all at once but
    sendPacketWithBatchResponse
    never returns and I don't know why
    t
    • 2
    • 8
  • a

    Andrea Giuliano

    12/12/2020, 5:31 PM
    Hi folks, I was trying to reproduce a case where coroutines and thread local don’t play well together. I wanted to try out using the threadlocal in a coroutine without using the extension function asContextElement() to see it breaking :) Now, as you can see from the snippet I launch a bunch of coroutines in half the threads I spawn and I put the other half to sleep. I wanted to prove that a suspending coroutine could wake up in a thread that was sleeping, leaking the thread local value. What happens instead is that the coroutines run all in the thread 2 (which was surprising to me ) and all of them prints null when reading the thread local value. Now I guess that happens because somehow threadlocal gets cleared, is that correct? What can I change to make sure the coroutines read the wrong value? (yeah I know, but I’m just experimenting)
    Untitled
    t
    • 2
    • 11
  • c

    christophsturm

    12/13/2020, 10:15 AM
    What’s the most idiomatic way to transform a flow with multiple threads? Let’s say I have a flow that contains suspend lambdas and I want to transform it to a flow that contains the result of those lambdas, but do it with 16 threads. I know how I would do it with channels, but aber flows more suitable?
    d
    o
    g
    • 4
    • 6
  • a

    Aness Iqbal

    12/13/2020, 4:26 PM
    Hi there, I need to go to particular destination/dialog in my app when ever the user receives HTTP error 401. Is it possible to observe/post that error from a simple kotlin class to a host activity, doesn't matter whichever fragment I am on? I do not want to abuse live data for this as this condition may only occur sometimes. Any kind help would be appreciated.
    l
    • 2
    • 2
  • t

    Tymmm1

    12/13/2020, 9:25 PM
    Hey, anyone aware of a way to
    collect
    just once from a
    StateFlow
    or
    SharedFlow
    ? One can call
    cancel()
    on the job of the coroutine that is collecting but that seems a bit cumbersome...
    t
    t
    • 3
    • 12
  • n

    Nikky

    12/14/2020, 9:34 AM
    how can i run my application with a limited number of cores? i seem to run into a weird issue on google cloud run probably related to having only 2 vCores
    w
    • 2
    • 2
  • r

    Rob

    12/14/2020, 7:41 PM
    I’m doing multiple concurrent API calls. It reads better with awaitAll() and destructuring but the types of the results are upcast to Any. Using await() looks uglier IMO but keeps the type information. Is there a way that reads like the former but still retains the type information like the latter?
    Untitled.kt
    t
    m
    • 3
    • 4
  • m

    mng

    12/14/2020, 10:41 PM
    I recently created a Timer that is handled through Coroutines, encapsulated as a
    TimerFlow
    object. I wanted to Unit Test this object but I stumbled across a problem, because I am exposing a
    SharedFlow
    for every “tick” of the Timer I am having trouble testing it since the
    replay
    value is set to 0. What are the best practices in regards to setting up a Timer like I am here, should I even use a
    SharedFlow
    to expose every tick or should I be using something else? If the approach I am using is correct, what would be the proper way for me to test this?
    z
    k
    • 3
    • 9
  • n

    Nikky

    12/15/2020, 9:57 AM
    i made a chunked flo operator and it seems to work fine in testing but for some reason only when deployed to google cloud run it shits itself and code executed through it takes 100+ times longer to complete afaik the cloud run VMs are limited to 2 cores, so i am guessing it is running into a parallelism limits on the default dispatcher just have no idea how my code triggers that.. because calling it directly (without the chunker operator and buffering) works fine https://gist.github.com/NikkyAI/025436616e81ff0a1711a6144fba0066 any help in suggestions on how to reproduce this locally or what i might have overlooked are appreciated
    m
    c
    • 3
    • 48
  • b

    brandonmcansh

    12/15/2020, 3:56 PM
    so I'm curious if there is an operator that is opposite of
    combine
    ?
    z
    • 2
    • 1
  • r

    Rob

    12/15/2020, 5:07 PM
    I’m getting this compiler crash when compiling this suspend function that I’ve simplified for illustration. Where should I report the bug?
    private val events: MutableSharedFlow<Unit> =
        MutableSharedFlow()
    
    fun foo(): Pair<String, String>? = null
    
    private suspend fun bar(): String = events
        .transform {
            emit(
                foo()
                    ?.let { it.first }
                    ?: return@transform
            )
        }
        .first()
    Untitled
    • 1
    • 1
  • t

    Tower Guidev2

    12/16/2020, 12:48 PM
    Im investigating the use of corountines in my current Android project. Specifically
    kotlinx.coroutines.channels.actor
    in my Android `androidx.work.CoroutineWorker`(s). What I am trying to achieve is that my Worker makes multiples calls to a remote API endpoint and each API response is sent to an actor channel to be processed on another thread so that I can immediatley start the API call for subsequent pages of data I have these message types
    sealed class Message {
    class Responsible(val value: Response<List<MyApiData>>) : Message()
    class GetValue(val deferred: CompletableDeferred<Int>) : Message()
    }
    This Actor
    fun CoroutineScope.persistActor() = actor<Message>(context = Dispatchers.Unconfined, capacity = Channel.UNLIMITED) {
    for (msg in channel) {
    when (msg) {
    is Message.Responsible -> managePage(msg.value)
    is Message.GetValue -> msg.deferred.complete(1)
    }
    }
    }
    private lateinit var persister: SendChannel<Message>
    each page returned from my API is processed by this recursively called function:-
    private suspend fun managePages(accessToken: String, response: Response<List<MyApiData>>) {
    when {
    result != null -> return
    response.isSuccessful -> persister.send(Message.Responsible(response))
    else -> {
    manageError(response.errorBody())
    result = Result.failure()
    return
    }
    }
    response.headers().filter { it.first == HTTP_HEADER_LINK && it.second.contains(REL_NEXT) }.forEach {
    val parts = it.second.split(OPEN_ANGLE, CLOSE_ANGLE)
    if (parts.size >= 2) managePages(accessToken, service.documents(accessToken, parts[1]))
    }
    }
    Once all the pages have been retrieved from the remote end point I execute the following code to await the actor to complete persisting the returned data
    val completed = CompletableDeferred<Int>()
    persister.send(Message.GetValue(completed))
    println("Counter = ${completed.await()}")
    persister.close()
    what I am concerned about 1). is this a "good" approach? 2). Does my worker wait for all data to be persisted before completing? 3). What improvements could I make?
    g
    r
    • 3
    • 14
  • d

    Dariusz Kuc

    12/16/2020, 5:33 PM
    Hello 👋 Just wondering whether this difference in behavior is expected, i.e. given flow <-> publisher interop
    public fun <T : kotlin.Any> org.reactivestreams.Publisher<T>.asFlow(): kotlinx.coroutines.flow.Flow<T>
    public fun <T : kotlin.Any> kotlinx.coroutines.flow.Flow<T>.asPublisher(): org.reactivestreams.Publisher<T>
    This is valid
    // inferred -> flow: Flow<Any?>?
    val flow = when (val publisherOrFlow: Any? = fetchValue()) {
        is Publisher<*> -> publisherOrFlow.asFlow()
        is Flow<*> -> publisherOrFlow
        else -> null
    }
    Yet this is invalid
    // inferred -> publisher: Publisher<*>?
    val publisher = when (val publisherOrFlow: Any? = fetchValue()) {
        is Publisher<*> -> publisherOrFlow
        is Flow<*> -> publisherOrFlow.asPublisher() // <-- issue here -> inferred type Any? is not a subtype of Any
        else -> null
    }
    s
    • 2
    • 3
  • f

    Florian

    12/17/2020, 7:58 AM
    Is there something like
    flatMapLatest
    that I can trigger explicitly and only once? I want to switch a Flow to another Flow if a certain condition is met
    b
    g
    w
    • 4
    • 11
  • l

    Lauren Yew

    12/17/2020, 4:18 PM
    https://kotlinlang.slack.com/archives/C0922A726/p1608221419193900
    ✅ 1
    k
    • 2
    • 2
  • d

    Dominaezzz

    12/18/2020, 9:59 PM
    Is there a better way to do this
    scope + SupervisorJob(scope.coroutineContext.job)
    ? I just want to create a child coroutine scope.
    t
    z
    • 3
    • 3
  • l

    louiscad

    12/18/2020, 10:02 PM
    scope.launch { supervisorScope { ... } }
    which you can then extract as an extension function.
    d
    • 2
    • 1
  • f

    Florian

    12/19/2020, 7:44 AM
    https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/suspend-cancellable-coroutine.html Are the docs outdated? My
    continuation.resume
    requires a 2nd argument
    b
    • 2
    • 2
  • l

    Lilly

    12/19/2020, 10:42 PM
    Hi, I have the following suspending function:
    override suspend fun connect(
            scope: CoroutineScope,
            device: BluetoothDevice,
            uuid: UUID,
            secure: Boolean
        ) {
            dataSource.connectToSocket(device, uuid, secure) { socket ->
                scope.launch(<http://Dispatchers.IO|Dispatchers.IO>) {
                    try {
                        dataSource.listenToSocket(socket)
                    } catch (e: Throwable) {
                        Timber.tag(TAG).e("Error: ${e.message}.")
                        throw e
                    }
    
                }
                startCommunication()
            }
        }
    How can I pass the exception to the caller of connect so that the caller can catch this exception? My approach with a nested coroutine might be wrong: I need another coroutine here because
    dataSource.listenToSocket(socket)
    is a suspending function with a
    while (true) { ... }
    statement and therefore won't never return, but I have to call
    startCommunication()
    directly after calling
    dataSource.listenToSocket(socket)
    .
    z
    u
    • 3
    • 22
  • i

    Ivan Pavlov

    12/21/2020, 4:17 PM
    Hi guys, I have something like
    private val eventFlow = MutableSharedFlow<BotStatusChangeEvent>()
    
    override val events: Flow<Event> = eventFlow
    
    override fun sendEvent(event: Event) {
        coroutineScope.launch {
            eventFlow.emit(event)
        }
    }
    What is the correct way to test that if I do
    sendEvent(Event(1))
    sendEvent(Event(2))
    sendEvent(Event(3))
    I receive all events in
    events
    flow?
    d
    • 2
    • 1
  • c

    christophsturm

    12/22/2020, 11:45 AM
    how can i call launch from a suspend method method and not wait for it? if i wrap the launch call with coroutineScope {} it waits for the job to finish
    l
    • 2
    • 4
  • m

    Marc Knaup

    12/22/2020, 4:23 PM
    Is there any way / workaround to test
    kotlinx-coroutines-reactive
    -based coroutines using
    runBlockingTest
    ? The related issue (https://github.com/Kotlin/kotlinx.coroutines/issues/1204) and pull request (https://github.com/Kotlin/kotlinx.coroutines/pull/1206) seem to be abandoned for a long time.
    g
    • 2
    • 6
  • w

    WukongRework.exe

    12/22/2020, 11:17 PM
    Is there any way to launch onto different coroutinescopes inside a for loop so that every iteration of the for loop still doesn't block each other?
    c
    d
    m
    • 4
    • 16
  • s

    Shalom Halbert

    12/23/2020, 10:29 AM
    When
    launch
    is used, we use dispatchers
    IO
    and
    Default
    to run code asynchronously. Why is
    async
    run asynchronously if you do not run on one of those dispatchers? It's possible I'm misunderstanding something.
    c
    s
    • 3
    • 4
Powered by Linen
Title
s

Shalom Halbert

12/23/2020, 10:29 AM
When
launch
is used, we use dispatchers
IO
and
Default
to run code asynchronously. Why is
async
run asynchronously if you do not run on one of those dispatchers? It's possible I'm misunderstanding something.
c

Circusmagnus

12/23/2020, 11:53 AM
asynchronously does not mean
in different threads
It just means, that they do not depend on each other, are not synchronized in any way. They may still run in parallel OR be just interleaved on single thread. suspend functions may, well... suspend their execution - waiting for something. This does not block a thread. So, during this suspension, other functions / coroutines may be run on this thread. And, when they finish, our suspend function may resume in the very same thread. Considering code
suspend fun one() {
   delay(100)
}

suspend fun two() {
  callSomeOtherSuspendFun
}


singleThreadScope.launch { 
   doSth()
   one()
   doSomeOtherThing()
 }

singleThreadScope.async { two() }
We are on single thread. The launch will start first. But soon enough it will suspend for 100 milliseconds. From this moment our async may start executing. It too cuould get suspended, because it is calling suspending function - making room for launch to resume its execution. 

So conceptually, both launch and async are executing at the same time. We cannot know, which one will finish first. They are asynchronous, even, when run on single thread.
That way, if you are on android with Room and Retrofit, you do not have to think about threading at all. Just launch your data-fetching coroutines in
viewmodelScope
(which is run on Dispatchers.Main). They will soon enough suspend, waiting for network calls / db queries to complete. And while they are suspended, other data fetching-corotuines may run on Main Thread. What is more - UI can run on Main thread too, uninterrupted. As long as you are not calling any blocking functions, you are free to go on Main Thread, and just forget about threading completely. *blocking function - function, which will execute for a considerable time, bloking a thread. suspend functions exposed by Room or Retrofit are not blocking, and can be called on Main Thread no problem.
So, IMHO best practice is to: • avoid / wrap blocking functions in
withContext()
• wrap non-blocking callback APIs in
suspendCancellableCorotuine
- which will make coroutine suspend until called back by callback •
launch
and
async
without any Dispatcher specified. If execution needs to be switched to different thread, assume, that
suspend fun
, which you are calling, has taken care of that (via
withContext()
or
suspendCancellableCoroutine
)
s

streetsofboston

12/23/2020, 1:53 PM
Yup, Asynchronous != Parallel You can run asynchronously on a dispatcher with only one thread. The current call may suspend and start executing (resuming) an other suspended call. When that one is done, it may resume the first call again. Like a queue of tasks served by a single thread, being served and run one at a time. With multiple threads in a dispatcher, this not only happens asynchronously, but they may run in parallel as well. Asynchronous is; not finishing one call/function and starting or resuming another one. Doesn't say anything about being parallel or not. Parallel is; calls run at the same time. Often this implies they run asynchronously as well, but not necessarily.
View count: 3