Is it safe to read from an `InputStream` in a `flo...
# coroutines
s
Is it safe to read from an
InputStream
in a
flow { }
builder? Getting warnings from IntelliJ about inappropriate blocking calls.
s
If you have a blocking call inside your
flow { … }
builder, the collector may block as well, since its scope’s dispatcher will be used to run the flow’s builder code.
g
It will block consumer until you apply explicit dispatcher on flow using flowOn operator
s
So I want
flowOn(<http://Dispatchers.IO|Dispatchers.IO>)
?
👌 2
I’m also using a STAX parser to read from an InputStream. I gather I should do the same with that to prevent it from blocking consumers?
I’m confused why this is an issue though. Flows are cold and unbuffered. Consumers execute the entire pipeline to get each value.
s
But blocking code in the flow (producer) can cause the consumer to block, since they would use the same dispatcher. With the
flowOn
you can prevent that
s
In other words, the consumer’s pool might be able to do other work but instead is blocked by the flow operator? Does
flowOn
have a buffer to resolve this?
s
No buffer. I uses suspend callbacks.
Instead of being blocked, you collector will be suspended.
s
Ah I see
Ok thanks. Hopefully that will clear the warning.
g
One more way, is avoid calling blocking code directly from flow, instead you can wrap this blocking code to suspend function with dispatcher, so flow itself will not block, but it just a matter of style and particular case
s
That’s why Flow don’t have backpressure issues like Rx does…
s
Does wrapping blocking calls in suspend properly prevent parent Coroutines from blocking?
Unless you are specifically forking with
launch
or
async
I didn’t think this was the case
g
If suspend function itself is not blocking, yes
s
The warning/linting system may not be that smart. I can detect a
withContext(<http://Dispatchers.IO|Dispatchers.IO>)
and remove the warning, but I doubt it can figure out the
flowOn(<http://Dispatchers.IO|Dispatchers.IO>)
to remove the warnings….
g
Don't use launch, use withContexy
s
@streetsofboston Plus I believe
withContext
is illegal in a standard flow
g
Right
s
You can’t emit from a different scope, but I think you can emit from a different context, correct?
Ah…. I guess you can’t do that 🙂
g
withContext also create scope, so it's not allowed
s
channelFlow
exists for this purpose but I think most uses of it are code smell
s
It perfectly fine to use if you want to emit data from plain non-suspending callbacks
g
I think flowOn is just the easiest solution
1
☝️ 2
s
This question has gone a bit off the rails but just to conclude, if you’re bridging callbacks
callbackFlow
is designed specifically for that purpose.
g
Yes, because callbackFlow checks whether you called awaitClose in the end
s
IIRC, that is the only difference between the channelFlow and callbackFlow, correct?
g
AFAIK, yes
g
I don't think that usage callback/channel flow would be better in this case, it created for concurrent emit from different threads, you will also pay price for it, which doesn't make a lot of sense if just want emit from some blocking loop like reading from a stream