Hello there! I made some measures and coroutines l...
# coroutines
e
Hello there! I made some measures and coroutines loose to parallelStream when they deal with parallel processing of collection elements. It’s sad 😔 Kotlin v1.3.72
3
g
It really depends on what kind operation you are doing, parallelStream is perfect for CPU intensive non-async operations, it’s directly optimized for it using fork-join pool Coroutines (also depends what kind coroutines) is to control async operations and will not will optimized parallelStream if you just do a bunch of parallel computations which anyway block thread But in general would interesting to see what you particularly your are doing and how you measure
e
https://pl.kotl.in/0Twe1idr4 if you’re intersted
g
You have very primitive implementetation of coroutines, it’s not different from just launching a bunch of threads and join them it’s not really a case (just a heavy computation on a bunch of threads) where you would expect coroutines to win parallelStream Also there are so many things there which are just not equal, for example ForkJoinPool used for parallelStreams is not the same as your straight forward dispatcher with Runtime.getRuntime().availableProcessors()
And I’m not even talking about way how you benchmark it
but I still would say, parallelPool is perfect for this kind operation (run many parallel blocking CPU intensitive operations as efficient as possible)
e
please, show some code to make this implementation of coroutines not so primitive
i used all that i had found useful in this situation
it’s a bit hard to benchmark spring+kotlin. i continue to find a way to do that
g
as I said, it depends on your use case
if you want to parallel blocking CPU intensive operation just use fork join
but if you really have async operations, than parallelStream will not work, it’s purely blocking abstraction, this is the case for coroutines
coroutines do not add any value for your example, just a useless abstraction to run a few threads on a fixed thread pool
You have very primitive implementetation of coroutines
It’s really bad explanation, not implementation of coroutines, but usage of them just as a wrapper on top of thread, this would be worse even without coroutines if you would compare it with parallelStream() which has own speciailized thread pool with job stealing mechanism
e
is it possible to use forkjoinpool as coroutines pool? i’ve found only fixed, single and global ones? google keeps silence. the fixed one showed the best perfomance… global one is a lot worse
g
global? you mean GlobalScope?
e
i mean the way that i don’t specified a pool at all
g
Well, short answer yes, you can use ForkJoinPool.commonPool().asCoroutineDispatcher()
i mean the way that i don’t specified a pool at all
Correct, because you run by default on DefaultDispatcher, which you shouldn’t really block and it just doesn’t do the same what parallelStream is doing
e
woohoo! interesting
g
Problem of your example not only in dispatcher, it’s just looks pointless to use coroutines for what you doing in your example
e
yep, i see. i hoped that it would have been more coroutines than threads in par stream. but theese tasks are more cpu bounded than i have expected(
g
yep
it’s fine to use coroutines for this, just because it’s very convinient, even for CPU bound tasks, but it makes sense as part of bigger asyncronous code, not just to launch a few threads
e
convinient? in our project we do not use them at all because there is no place for them 😭
i’ve tried and lost
g
yes, extremely convinient if you have a bunch of asynchronous code %)
if all your code is blocking, it would be an improvement in terms of code, just because asyncronous code of coroutines look as blocking code, which allows to write much more simple non-blocking code
e
sounds like it’s a lot more pythonic async/await than golang goroutines
g
it can do both
and more natural than async/await
e
thx! continue trying to master them
e
Not the prettiest proof-of-concept, and somewhat contrived. But using the following code I get a difference of about 200ms tops either way. Which I would say for most use-cases is negligible compared to things such as http-calls/db-access etc. https://pl.kotl.in/rRsZs0ETN
g
Thread pool average duration: 192432 Coroutine average duration 147564 Coroutine difference -44868 ns -44 ms
See, sometimes coroutines are even faster But I would like to point out, that you cannot rely on such code as benchmark, you need correctly configured benchmark harness which will handle all usual pitfalls of JVM benchmarks
e
Thread pool average duration: 91329 Coroutine average duration 181858 Coroutine difference 90529 ns 90 ms
if somebody helps me to set up true benchmark for kotlin+plus spring… i cannot start spring app from jmh(((
g
Why do you need spring in this example at all?
e
because i’m working with it. and i wanna benchmark a small piece of an internal process. a hibernate query is important to be included in benchmark among others.
g
But why? You do not measure hybernate
Also I still think this comparison is pointless
If you want to parallel database requests invest into usage of asynchronous drivers for database, it will really help with performance (at least in some workloads) and it works perfectly with coroutines
Also I believe Spring provides support of reactive DB api out of the box and even support coroutines and Flow
e
yes, i do
Copy code
b.findAllByaName(it.id)
it’s a hiber query
g
If you want to measure performance of database compare it with async api, not with blocking
I just want to point out that Micro benchmarking is useless if you want to measure such complex system as database, you should profile it on application level, with close to real life task, to cover all possible bottlenecks
e
hmpf… i benchmarks coroutines against parallesStreams. but the impact of db query is important.
g
Measuring different implementation one based on pure blocking hybernate and another on something like spring R2DBC
¯\_(ツ)_/¯
e
what?
it’s hyber every time
that’s the point
g
It just looks for me that you measuring not what you actually should measure with implementation which shouldn't be used for this case
I just want to say, that you shouldn't expect some kind improvement in this case, coroutines will not make your thread pool run faster, just add unnecessary abstraction on top of it
e
yep! this point i caught yesterday 😉