blob: 636b334dbfb78e68a1993caf69ae2a5e0c44f3a5 [file] [log] [blame]
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow
import benchmarks.flow.scrabble.flow
import io.reactivex.*
import io.reactivex.functions.*
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import org.openjdk.jmh.annotations.*
import java.util.concurrent.TimeUnit
import java.util.concurrent.Callable
@Warmup(iterations = 7, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 7, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(value = 1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Benchmark)
open class NumbersBenchmark {
companion object {
private const val primes = 100
private const val natural = 1000L
}
private fun numbers(limit: Long = Long.MAX_VALUE) = flow {
for (i in 2L..limit) emit(i)
}
private fun primesFlow(): Flow<Long> = flow {
var source = numbers()
while (true) {
val next = source.take(1).single()
emit(next)
source = source.filter { it % next != 0L }
}
}
private fun rxNumbers() =
Flowable.generate(Callable { 1L }, BiFunction<Long, Emitter<Long>, Long> { state, emitter ->
val newState = state + 1
emitter.onNext(newState)
newState
})
private fun generateRxPrimes(): Flowable<Long> = Flowable.generate(Callable { rxNumbers() },
BiFunction<Flowable<Long>, Emitter<Long>, Flowable<Long>> { state, emitter ->
// Not the most fair comparison, but here we go
val prime = state.firstElement().blockingGet()
emitter.onNext(prime)
state.filter { it % prime != 0L }
})
@Benchmark
fun primes() = runBlocking {
primesFlow().take(primes).count()
}
@Benchmark
fun primesRx() = generateRxPrimes().take(primes.toLong()).count().blockingGet()
@Benchmark
fun zip() = runBlocking {
val numbers = numbers(natural)
val first = numbers
.filter { it % 2L != 0L }
.map { it * it }
val second = numbers
.filter { it % 2L == 0L }
.map { it * it }
first.zip(second) { v1, v2 -> v1 + v2 }.filter { it % 3 == 0L }.count()
}
@Benchmark
fun zipRx() {
val numbers = rxNumbers().take(natural)
val first = numbers
.filter { it % 2L != 0L }
.map { it * it }
val second = numbers
.filter { it % 2L == 0L }
.map { it * it }
first.zipWith(second, { v1, v2 -> v1 + v2 }).filter { it % 3 == 0L }.count()
.blockingGet()
}
@Benchmark
fun transformations(): Int = runBlocking {
numbers(natural)
.filter { it % 2L != 0L }
.map { it * it }
.filter { (it + 1) % 3 == 0L }.count()
}
@Benchmark
fun transformationsRx(): Long {
return rxNumbers().take(natural)
.filter { it % 2L != 0L }
.map { it * it }
.filter { (it + 1) % 3 == 0L }.count()
.blockingGet()
}
}