Hi, I have a question about performing CPU bound o...
# coroutines
p
Hi, I have a question about performing CPU bound operations Should I be using
Dispatchers.Default
or create separate scope with fixed thread pools equal to number of cores? what are the pros and cons? what are the criteria's to choose between one of this approach? for ex. Library writer, App writer etc. I have posted detailed explanation and my use cases here https://stackoverflow.com/questions/63915078/can-i-use-dispatchers-default-for-blocking-cpu-bound-operations
l
Please, read the doc of
Dispatchers.Default
, it answers your question, telling that it's designed for that.
p
Yes, I have done good amount of research on the topic! Wanted to understand if theres any gotchas I should be aware of! For example, because this is globally available, there could be possibilities that any third part library dependency is using it! May be they are accidentally doing IO operations on
Default
etc.
l
A third-party library could also call
exitProcess()
or
System.exit()
. In all cases, it needs to be fixed.
p
And if you create your own Dispatcher, then you can cope up with third party libs doing bad operations on default pool in some cases
I hope, you have read my stackoverflow question I am all in to use
Default
dispatcher, but we are having debate within the team, hence the question
l
I hope, you have read my stackoverflow question
I did not because the answer to the title was "yes".
p
Ok, so jumping to conclusion based on the title does not seem right Theres very little info you can provide in the title
l
Doing your best to cope with bad libraries is not the right strategy IMO. They should avoid being that bad, and be fixed or shamed and dropped if they dare to be this bad (granted it's on the JVM where you have access to
<http://Dispatchers.IO|Dispatchers.IO>
).
p
That was one example, I am just looking for any gotchas, pros/cons
r
The title of your SO says "blocking CPU bound" operation but your details don't talk about blocking ops, just CPU bound ops. Which is it?
l
Gotcha is avoid bad libraries because their power might be limitless.
p
To give another example, having separate scope backed by your own thread pool provides you isolation and you can take control of complete lifecycle, maybe supervise
l
You can make an app or a server lag with just a library, even if it doesn't use
Dispatchers.Default
.
True isolation is process isolation, and even that has limits.
r
If you are CPU bound, at the end of the day it doesn't really matter where you run them. You're gonna be pegging your CPU regardless.
p
I completely agree with you @rocketraman Thats one of the point I brought in the discussion within the team
and currently went ahead with Dispatchers.Default
But know that, we are building library and not application
l
@rocketraman Well, not really actually. What manages running your code will define the share of the CPU your code is allotted versus other code running in the process, and on the machine. But if there's a bad actor in your code, or next to it, that interferes with the available share, then it needs to be found and hunted down.
This responsibility is on the consumers of the library if your library already does its best to not starve the CPU.
r
True, but I don't think his scenario is a bad actor scenario, that was just a (bad) example he gave.
If he runs his CPU bound workload in Dispatcher.Default, or creates a separate coroutines dispatcher, its gonna be the same result.
l
By bad, I don't mean malware but bad by misuing shared resources in the runtime.
r
I know
Like I said, I don't believe that is OPs scenario
p
Here is my post from my internal chat, that should clarify it ๐Ÿ˜‰
Copy code
default/global are meant for cpu bound operations because they follow no of threads roughly equals to no of cores
having another thread pool will not solve a problem if there are 8 CPU bound operations already running and you want to start 9th operation (that will have to wait) (here assumption is, machine has 8 cpu cores)
๐Ÿ‘ 1
r
@Pritam Kadam I think you confused people by throwing the word "blocking" in your OP.
p
i think blocking CPU bound is correct for example, Matrix multiplication, BigInteger.probablePrime from Roman's example from this blog https://medium.com/@elizarov/blocking-threads-suspending-coroutines-d33e11bf4761
maybe I should just rephrase it to
CPU Intensive
to avoid confusion
@louiscad I dont think such meta level statement helps at all in any discussion
True isolation is process isolation, and even that has limits.
r
"CPU bound" is clear. Roman distinguishes between work that is "blocking" via being CPU bound, and blocking vs IO. I know you know this, but his use of the term "blocking" for the former is explanatory. When you use that term casually most people will assume IO blocking or blocking by a poorly coded library.
l
@Pritam Kadam I think it was fair regarding your example of a library that would run blocking I/O against
Dispatchers.Default
instead of
<http://Dispatchers.IO|Dispatchers.IO>
or something else in the same process of your library.
r
The process isolation point is a valid one @Pritam Kadam I think. You can always run CPU bound work in a separate process, with cgroups to limit how much of the machine it can use. That way the machine is guaranteed to have resources for other work, like request handling.
๐Ÿ‘ 1
l
Excatly, despite the counterpart of having to do some sort of IPC to communicate (even if just basic command args and exit code)
p
That I understand, it felt more like sarcasm
l
Maybe it felt that way, but it wasn't ๐Ÿ™‚
Maybe my style of writing was oriented by how highly exactly I think of bad libraries that would affect yours or its users badly ๐Ÿ™ƒ But no offense intended, and I hope you have a clearer view of the risks and the options now ๐Ÿ˜‰
r
If your CPU bound work has the option to be broken up into smaller chunks, you can
yield
between the chunks to give other coroutines the ability to run. It'd be interesting to see if that worked well enough to avoid the need for process isolation.
โž• 1
p
@louiscad I was just probing to get more views, more ideas on the topic And the point about 3rd party libs, i have similar opinion, here is another snippet from internal discussion (this statement was in context of scala's global execution context)๐Ÿ˜‰
2. As it is available globally, anyone could have used it in 3rd party libs for doing IO
though we should not be using lib with such quality but its hard to find out ;)
(this is fine as long as they are doing cpu ops)
@rocketraman we are building kotlin dsl backed by coroutines which runs on single thread That way you can freely mutate variables in the callback or any part of the script Now we wanted to recommend pattern for our users to do IO/CPU bound ops which definitely cant be done on single thread So we dont know what kind of cpu/io ops our users might want to run
r
Maybe you want to expose that as part of your DSL then? i.e. have a way for them to essentially do
withContext
but more limited to the options you want to give them.
Depends on how technical your users are I guess
p
our users are astronomers, so you can expect them to know little things about coroutines and all Our scripting env will hide all these complexities
r
You can't hide it all, as you need to know where to run stuff. Unless your DSL consists solely of higher level operations for which you know the ideal execution context. However, you stated "we dont know what kind of cpu/io ops our users might want to run".
p
Currently we are suggesting to write separate suspend function and wrap that within `
Copy code
withContext(Dispatchers.Default)
for cpu bound task and call that function from script
r
In this context, I'd probably expose my own dispatcher. For now, you can simpy alias it to DefaultDispatcher, but exposing your own gives you the option to do other things in the future. Like run that code in a separate process.
p
Yes, we might end up doing exactly that
when you say separate process, do you mean running that in different JVM? forking another jvm from one was not a fun experience I had in the past๐Ÿ˜ฃ
r
Yes, different JVM. Don't fork -- use some IPC mechanism. Like gRPC or rsocket or something.
p
yes, might not work for us most probably script and IO/CPU bound ops I am talking about will be tightly coupled
r
Is it multi-tenant? ie. do you want to make sure one astronomers work does not impact anothers?
p
No, I mean, one script will have some data structures, immutable variables which they might want to use in these cpu intensive operations back and forth
and that could be anything