I am trying to execute following code:
val jobs = listOf(...)
return runBlocking(CommonPool) {
val executed = jobs.map {
async { it.execute() }
}.toTypedArray()
awaitAll(*executed)
}
where jobs
is the list of some Supplier
s - in synchronus world this should just create, for example, list of ints.
Everything works fine, but the problem is the main thread is not utilized. Bellow screenshot from YourKit:
So, the question is - how can I utilize main thread also?
I suppose runBlocking
is the problem here, but is there other way to receive the same result? With Java parallel stream it looks far more better, but the main thread is still not utilized entirely (tasks are totally independent).
UPDATE
Ok, maybe I have told you too few things. My questions came some time after watching Vankant Subramaniam presentation : https://youtu.be/0hQvWIdwnw4. I need maximum performance, there is no IO, no Ui etc. Only computations. There is only request and I need to use all my available resources.
One think which I have is to set paralleizm to thread count + 1, but I think it is rather silly.
Just because there is no work being run on this explicit thread doesn't mean that device is not running other threads on the same core.
It's actually better to have your
MainThread
idle, that will make your UI more responsive.I tested the solution with Java 8 parallel streams:
I found the CPU utilization to be reliably on 100%. For reference, I used this computation job:
Note that its duration varies randomly from zero up to the time it takes to perform 100,000,000 FP multiplications.
Out of curiosity I also studied the code you added to your question as the solution that works for you. I found a number of issues with it, such as:
I wrote some code of my own and added code to benchmark the Stream API one-liner against it. Here it is:
Here's my typical result:
The results are similar, but one line of code still beats 50 lines of code :)
async() without any parameters using DefaultDispatcher and will take pool from parent, so all the async calls executed in CommonPool. If you want different set of threads to run your code, create your own pool. While it's usually good practice to not utilize main thread with computation, but depends on your usecase.
First, I'd like to empathize that utilizing main thread usually doesn't serve any practical purpose.
If your application is fully asynchronous, then you'll have only single (main) thread blocked. This thread does consume some memory and adds a bit of extra pressure on scheduler, but the added impact on performance would be negligible and even impossible to measure.
In practical java world it's almost impossible to have fixed number of threads in the JVM. There are system threads (gc), there are nio threads, etc.
One thread doesn't make a difference. You're fine as long as the number of threads in your application doesn't grow unconstrained with increased load.
Back to the original question.
I don't think there is a concise way to utilize main thread in this kind of parallel processing tasks.
For example, you can do the following:
Basically, is a simple producer/consumer implementation where main thread serves as one of the consumers. But that leads to lots of boilerplate though.
Output: