I'm asking this question solely to better understand how kotlin sequences work. I thought I had a solid grasp, but I cannot explain what I observed in a short test by what I know, so obviously I have a misconception somewhere.
My goal was to do a quick benchmark to compare the performance of lists vs. sequences when filtering for a criteria and then taking the maximum value of the result. This is an operation that occurs fairly often in some code I have, and I'm trying to decide whether or not it's worth rewriting it to use sequences instead of lists. It seems it would be, as sequence is consistently faster, but that is not the question here.
Rather, I would ask you to explain to me how the below described "artifact" can come about.
First of all, here's the complete test I ran:
fun `just checking the performance of sequences`() {
val log = logger()
var totaldif = 0L
var seqFasterThanList = 0
(1..1000).forEach {
val testList = (1..6000000).toList().shuffled()
val testSequence = testList.asSequence()
// filter and find max
val listDuration = measureTimeMillis {
testList.filter { it % 2 == 0 }.max()
}
val sequenceDuration = measureTimeMillis {
testSequence.filter { it % 2 == 0 }.max()
}
log.info("List: {} ms; Sequence: {} ms;", listDuration, sequenceDuration)
if (sequenceDuration < listDuration) {
seqFasterThanList++
totaldif += (listDuration - sequenceDuration)
}
}
log.info("sequence was faster {} out of 1000 runs. average difference: {} ms",
seqFasterThanList, totaldif / seqFasterThanList)
}
The results mostly looked like this:
List: 299 ms; Sequence: 217 ms;
List: 289 ms; Sequence: 211 ms;
List: 288 ms; Sequence: 220 ms;
Except, every once in a while, about 1 in 20, the result looked more like this:
List: 380 ms; Sequence: 63 ms
As you can see, in these cases the operation was vastly faster. This is the kind of behaviour I would expect on operations like find or first, which can terminate early once they find a match. But by its very nature, max has to traverse the entire sequence to guarantee the result. So how is it possible that some times it can find a result more than 3 times as fast as it usually requires, with the same number of elements to traverse?