https://kotlinlang.org logo
#coroutines
Title
# coroutines
v

vineethraj49

09/14/2019, 9:50 AM
Hi, 1. when does a Job get completed? once all the `.launch`ed job children get completed? 2. can a job indefinitely block a parent context if it is still .isActive`
e

elizarov

09/14/2019, 9:51 AM
When you call
job.compelete()
(or
job.cancel()
) and all its launched children complete, too.
v

vineethraj49

09/14/2019, 9:55 AM
my bad, slack posted this before I was able to post the other questions; 2. can and will a job block the parent from completion if it is still
.isActive
3. I am trying to implement a simple worker pool, post all the `.launch`es complete, the job is still
.isActive
, but (see 4) 4. the job is blocking the parent only if the job is spawned with
parent=coroutineContext
rather than
parent=Dispatchers.Default
5. I am not able to access the
.complete()
function on the job interface
e

elizarov

09/14/2019, 9:56 AM
complete
is available on
CompletableJob
that the
Job(...)
constructor returns.
It is convenient and encouraged to wrap your
Job
into a
CoroutineScope
(use
CoroutineScope(...)
constructor). This way you can do
myScope.launch { ... }
which is more idiomatic.
v

vineethraj49

09/14/2019, 10:09 AM
ah I figured why I am not able to access `.complete`; I’m stuck on
kotlinx-coroutines-core:1.1.1
e

elizarov

09/14/2019, 10:09 AM
Update to
1.3.0
, then. Do you have any roadblocks?
v

vineethraj49

09/14/2019, 10:10 AM
versions are locked by a single parent across the org ¯\_(ツ)_/¯
e

elizarov

09/14/2019, 10:11 AM
The workaround is to use
CompletableDeferred<Unit>()
as your job.
v

vineethraj49

09/14/2019, 10:28 AM
ok, so I changed the logic a bit; since I realized I do not need a specific (context + Job) 1. switched to
: CoroutineScope by CoroutineScope(context)
constructor 2. stored the `.launch`’ed workers in a
val workers: List<Job>
3. on my
.shutdown()
I do a
workers.joinAll()
which waits for completion and 4.
.shutdownNow
does
workers.map { it.cancelAndJoin() }
is there anything that does not seem very idiomatic for the same?
maybe I do not need to wait for a
.cancelAndJoin()
and just firing
.cancel
would suffice for
shutdownNow
e

elizarov

09/14/2019, 10:30 AM
2-4 are not needed. You can simply call
cancel
on the scope/job (it cancels all the children) and do
job.children.forEach { it.await() }
. No need to keep track of your children manually.
v

vineethraj49

09/14/2019, 10:32 AM
but since I am passing
coroutineContext
in the constructor, will that try to cancel children of that context as well?
v

vineethraj49

09/14/2019, 10:34 AM
ah, so it’s a new job for the given CoroutineScope that gets independently cancelled?
e

elizarov

09/14/2019, 10:35 AM
There's no new job if you already had a job in the context when you called
CoroutineScope(context)
Jobs form a hierarchy. Cancel parent and all children get cancelled automatically. You don't have to manually keep track of them. It won't harm, but there's simply no need to write all that code
v

vineethraj49

09/14/2019, 10:41 AM
I am a bit confused; There is
class Foo(context) : CoroutineScope by CoroutineScope(context)
will have
.[Job]
as whatever is the
coroutineContext
passed to the ctor’s
.[Job]
is calling
Foo().cancel
not going to cancel the other running Job’s in parent?
e

elizarov

09/14/2019, 10:51 AM
It will cancel everything in parent. If you want a specific job to encompass coroutines created inside
Foo
, write:
Copy code
class Foo(context) : CoroutineScope by CoroutineScope(context + Job(context[Job]))
v

vineethraj49

09/14/2019, 11:16 AM
yes! I have ended up with the following:
Copy code
suspend fun shutdown() {
        tasks.close()
        coroutineContext[Job]?.children?.forEach { it.join() }
        coroutineContext.cancel()
    }

    fun shutdownNow() {
        tasks.close()
        coroutineContext.cancel()
    }
and this cancellation does not mess with my parent spawn’ed jobs
cool, thanks for the inputs and patience 🙂
5 Views