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

Mark

05/29/2019, 12:11 PM
Suppose I have
Copy code
suspend fun myFun() {
    repeat(100) {
        someSuspendingFunSpecifyingIODispatcher()
        someQuickNonSuspendingFun()
    }
}
At the top-level of myFun() is it better to have withContext(Dispatchers.IO), coroutineScope {} or leave it as it is?
g

gildor

05/29/2019, 1:10 PM
Leave it as it is
I see no reason to wrap to IO or creating new scope if you just use regular functions
m

Mark

05/29/2019, 1:12 PM
wouldn’t there be more potential context switching if the caller calls using, say, Main dispatcher?
g

gildor

05/29/2019, 1:12 PM
Why so?
m

Mark

05/29/2019, 1:13 PM
I’m guessing there would be some kind of switching from Main to IO each time someSuspendingFunSpecifyingIODispatcher() is called
g

gildor

05/29/2019, 1:13 PM
Sure
m

Mark

05/29/2019, 1:13 PM
but with withContext(Dispatcher.IO) there wouldn’t be
g

gildor

05/29/2019, 1:14 PM
Yes, but it will be on withContext, you just moved it a bit and create unnecessary scope and suspend point and make it less readable
Without any performance gain
m

Mark

05/29/2019, 1:15 PM
Just to be clear, I don’t mean the withContext() inside the repeat(), I mean at the top level
Copy code
suspend fun myFun() = withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
    repeat(100) {
        someSuspendingFunSpecifyingIODispatcher()
        someQuickNonSuspendingFun()
    }
}
Wouldn’t that run entirely on IO dispatcher? Surely more efficient?
g

gildor

05/29/2019, 1:17 PM
I see what you mean
Problem that you leak implementation details
Of someSuspendingFunSpecifyingIO
m

Mark

05/29/2019, 1:19 PM
For sure it’s a potential optimization. Knowledge that something will run in IO, means we have the option to choose a strategy knowing that.
g

gildor

05/29/2019, 1:21 PM
If this function is blocking (require run on IO) and it's private it would even more performant to do not make it suspend and do not switch any context, just keep it blocking and switch context before repeat
m

Mark

05/29/2019, 1:22 PM
Thing is, I have all these utility methods working on Files and InputStreams and I’m making them all suspend functions and wondering whether I should be putting withContext(Dispatchers.IO) at the top of each one. Or just at the lowest level.
Oh I see
g

gildor

05/29/2019, 1:22 PM
If it public general usage function and you want easily and safer use it from suspend function, that this function should switch context explicitly inside of the body
If you need performance for some higher level functions, than just use blocking functions to avoid suspend point creation, allocations and context switches
m

Mark

05/29/2019, 1:24 PM
Ok, so in general keep a bunch of private blocking functions and public suspend functions that choose the correct dispatcher
g

gildor

05/29/2019, 1:24 PM
Yes, this is how we try to organize such APIs
But again, if you want to make it a bit more performant
But careful with cancellation, check for isActive or call yield if you don't have other suspend calls between blocking calls to make it cancellation friendly
👍 1
m

Mark

05/29/2019, 1:27 PM
Do you use some kind of naming standard to distinguish between public suspend and private blocking functions? I can imagine there would be lots of cases where the former simply calls the latter (plus a withContext)
p

pakoito

05/29/2019, 1:29 PM
But careful with cancellation, check for isActive or call yield if you don't have other suspend calls between blocking calls to make it cancellation friendly
why do you need to check for this, shouldn't the next suspension at
someSuspendingFunSpecifyingIODispatcher
just not be triggered?
m

Mark

05/29/2019, 1:30 PM
I think he’s talking about the general case
g

gildor

05/29/2019, 2:42 PM
I'm talking about case when you some suspend function that calls many blocking APIs. If you call suspend functions nothing worry about
I usually call function that blocks with Blocking suffix to make it explicit
👍 2