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

Animesh Sahu

11/15/2019, 4:53 AM
What's the best way to run a coroutine environment application in jvm? Basic structure of application that i want is as shown
Copy code
fun main() {
    Foo()
}

class Foo {
    val bar = Bar()
}

class Bar() {
    // perform some long running tasks with some part dependent on foo
}
Case 1:
Copy code
fun main = runBlocking { //this: CoroutineScope
    Foo(this)
}
class Foo(scope: CoroutineScope): CoroutineScope by scope {
    val bar = Bar(this)
}

class Bar(val foo: Foo): CoroutineScope by foo {
}
Case 2:
Copy code
fun main = runBlocking { //this: CoroutineScope
    Foo(this)
}
class Foo(scope: CoroutineScope): CoroutineScope {
    override val coroutineContext = scope.coroutineContext
    val bar = Bar(this)
}

class Bar(val foo: Foo): CoroutineScope {
    override val coroutineContext = foo.coroutineContext
}
Case 3:
Copy code
fun main() {
    //just dont start coroutine here
    Foo()
}

class Foo: CoroutineScope {
    override val coroutineContext = Dispatchers.Default
    val bar = Bar(this)
}

class Bar(foo: Foo): CoroutineScope {
    override val coroutineContext = Dispatchers.Default
}
Or if there is a better way to create a coroutine driven application?
b

bdawg.io

11/15/2019, 5:10 AM
Case #3 uses a completely different dispatcher from the others. The others runs all tasks on a single thread. I would suggest #2 without a) using the scope provided by the
runBlocking
and b) not having Foo and Bar implement CoroutineScope directly. For example:
Copy code
suspend fun main(): Unit = withContext(Dispatchers.Default) {
    Foo(this)
}

class Foo(private val scope: CoroutineScope) {
    val bar = Bar(scope)
}

class Bar(private val scope: CoroutineScope) {

}
And that's only if you have a reason to provide the scope down. In most cases, it's probably better just to define suspending functions and using the
coroutineScope
coroutine builder.
Copy code
class Bar {
    suspend fun doSomething() = coroutineScope {
        val asyncOne = async { foo.doSomething(1) }
        val asyncTwo = async { foo.doSomething(1) }
        processResult(asyncOne, asyncTwo)
    }
}
a

Animesh Sahu

11/15/2019, 5:15 AM
@bdawg.io What's difference b/w these and do they have performace difference, since i saw only runblocking to start main in docs
Copy code
suspend fun main(): Unit = withContext(Dispatchers.Default) {
    Foo(this)
}

fun main = runBlocking { //this: CoroutineScope
    Foo(this)
}
b

bdawg.io

11/15/2019, 5:19 AM
runBlocking
blocks the current thread and provides it as the only thread backing the CoroutineScope.
withContext
, you're specifying the context (in this case the Default dispatcher to have more than one thread). AFAIK,
suspend fun main() { doSomething() }
is just a Kotlin compiler short-hand for
fun main() { runBlocking { doSomething() } }
z

Zach Klippenstein (he/him) [MOD]

11/15/2019, 4:37 PM
I think it’s slightly different –
suspend fun main
will start executing on the main thread, but if you look at
coroutineContext
it’s
EmptyCoroutineContext
, which implies
Dispatchers.Default
, and any coroutines started from the scope will be executed on the default pool. https://pl.kotl.in/HZUd3SohR
b

bdawg.io

11/15/2019, 5:09 PM
So in otherwords, all that was needed was
Copy code
suspend fun main() {
    Foo(this).doSomething()
}
interesting!
👍 2
d

Dico

11/16/2019, 11:49 PM
I prefer
private val scope = GlobalScope + Job()
And then using
scope
a

Animesh Sahu

11/17/2019, 3:08 PM
@Dico what does Job() do? and that + sign (im a newbie)
b

bdawg.io

11/17/2019, 3:41 PM
Job()
creates a job instance that you can use as a parent job to others. The
+
is for the
ContextElement
type, which allow you to merge multiple aspects of the
coroutineContext
to provide the context that you want for your
CoroutineScope
.
In his case, he’s creating a context with the
GlobalScope
(which is really just the
EmptyCoroutineContext
) and his own parent job. I’d recommend being explicit about which dispatcher you want though.
Copy code
private val scope = Dispatchers.Default + Job()
a

Animesh Sahu

11/18/2019, 11:24 AM
@bdawg.io byt what does job do, what is the purpose of doing that?
b

bdawg.io

11/18/2019, 3:55 PM
It’s a parent job to track all other jobs against. It’s how structured concurrency works. Everything is tracked through a hierarchy
a

Animesh Sahu

11/18/2019, 3:57 PM
any reference for more info?
d

Dico

11/19/2019, 4:33 AM
Dispatcher + Job is not a scope btw
2 Views