Why is offerInternal and takeFirstReceiveOrPeekClosed using such high CPU time?
See original GitHub issueI am experimenting with a project for using coroutines and channels under the hood for reactive-style data streams:
https://github.com/caleb-allen/Konko-Flow
The idea is that any (stateless) operator can be run concurrently. As an example:
val a = listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Flow.from(a)
.map { "$it says hi!" }
.forEach { println(it) }
Each stage would have coroutine(s) processing the operator, and channel(s) to send the data downstream:
[fromOp] -------- channel -------- [mapOp] -------- channel -------- [forEachOp]
Each “stage” is an operator plus a channel. A stateless stage may have multiple coroutines processing the operation, and a channel for each coroutine to pass the results down. We only need a single stream to show the issue.
Here is a jvm snapshot using VisualVM. This is using 1 stream. I’ve been digging through the source to figure out what is hanging but am at a loss. As you can see, AbstractSendChannel.send()
is taking significantly more time than the user code ChannelTest$collectTest$times$1$wordsCount$1.invoke()
, where the operation is being applied. I am using unlimited channels with LinkedListChannels. Am I misunderstanding or misusing channels?
Best,
Caleb
Issue Analytics
- State:
- Created 5 years ago
- Comments:6 (3 by maintainers)
Top GitHub Comments
I’ve used async-profiler and disabled debug mode which is enabled in tests by default.
Yes, that’s what I needed, thanks.
I’ve ran your test in a loop for a while and profiled it:
ChannelTest$
) takes ~30% of total execution timeIn pipeline
Flow.from(file).partition().flatMap().collect()
every source element is passed through 4 concurrent channels and up to 4 context switches, which is a performance killer. Currently our own channel implementation suffers from the same issue, https://github.com/Kotlin/kotlinx.coroutines/issues/285. As a solution, consider fusing all intermediate operations into one channel or build your library on top of kotlinx channel operators and wait until https://github.com/Kotlin/kotlinx.coroutines/issues/285 is fixed.No, in general your approach to build Konko-Flow pipelines is fine.
As an additional performance improvement we can provide specific
Channel
implementations such as array-basedOneToOneChannel
andOneToManyChannel
, but this improvement is negligible in comparison with operator fusing