Skip to content

Instantly share code, notes, and snippets.

@mingyang91
Last active December 22, 2023 08:01
Show Gist options
  • Save mingyang91/b2d02858cc30ef71b2ae61bb97cc8f3b to your computer and use it in GitHub Desktop.
Save mingyang91/b2d02858cc30ef71b2ae61bb97cc8f3b to your computer and use it in GitHub Desktop.
Compare concurrency control in Coroutine VS Reactive VS VirtualThread(a.k.a Loom)
package org.example
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import org.openjdk.jmh.annotations.*
import java.util.concurrent.TimeUnit
fun main(args: Array<String>) {
org.openjdk.jmh.Main.main(args);
}
@Warmup(iterations = 7, time = 1)
@Measurement(iterations = 5, time = 1)
@BenchmarkMode(Mode.All)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
@Fork(1)
open class Compare {
val scope = GlobalScope
val channel = Channel<CompletableDeferred<Unit>>(128)
init {
scope.launch {
channel
.receiveAsFlow()
.cancellable()
.flatMapMerge(16) {
flow<Nothing> {
delay(0)
it.complete(Unit)
}
}
.collect()
}
}
@Benchmark
fun reactive() = runBlocking {
val deferred = CompletableDeferred<Unit>()
channel.send(deferred)
deferred.join()
}
val wait = Semaphore(128)
val concurrency = Semaphore(16)
@Benchmark
fun kotlinSemaphore() = runBlocking {
wait.withPermit {
concurrency.withPermit {
delay(0)
}
}
}
val jwait = java.util.concurrent.Semaphore(128)
val jconcurrency = java.util.concurrent.Semaphore(16)
@Benchmark
fun loomSemaphore() = Thread.ofVirtual().start {
jwait.acquire()
jconcurrency.acquire()
Thread.sleep(0)
jconcurrency.release()
jwait.release()
}.join()
}
Benchmark Mode Cnt Score Error Units
Compare.kotlinSemaphore thrpt 5 5896.626 ± 195.969 ops/ms
Compare.loomSemaphore thrpt 5 326.712 ± 11.815 ops/ms
Compare.reactive thrpt 5 296.230 ± 44.611 ops/ms
Compare.kotlinSemaphore avgt 5 0.002 ± 0.001 ms/op
Compare.loomSemaphore avgt 5 0.040 ± 0.022 ms/op
Compare.reactive avgt 5 0.041 ± 0.011 ms/op
Compare.kotlinSemaphore sample 1949362 0.003 ± 0.001 ms/op
Compare.kotlinSemaphore:p0.00 sample ≈ 10⁻⁴ ms/op
Compare.kotlinSemaphore:p0.50 sample 0.002 ms/op
Compare.kotlinSemaphore:p0.90 sample 0.002 ms/op
Compare.kotlinSemaphore:p0.95 sample 0.003 ms/op
Compare.kotlinSemaphore:p0.99 sample 0.003 ms/op
Compare.kotlinSemaphore:p0.999 sample 0.084 ms/op
Compare.kotlinSemaphore:p0.9999 sample 1.426 ms/op
Compare.kotlinSemaphore:p1.00 sample 16.908 ms/op
Compare.loomSemaphore sample 825468 0.037 ± 0.001 ms/op
Compare.loomSemaphore:p0.00 sample 0.001 ms/op
Compare.loomSemaphore:p0.50 sample 0.032 ms/op
Compare.loomSemaphore:p0.90 sample 0.056 ms/op
Compare.loomSemaphore:p0.95 sample 0.070 ms/op
Compare.loomSemaphore:p0.99 sample 0.147 ms/op
Compare.loomSemaphore:p0.999 sample 0.485 ms/op
Compare.loomSemaphore:p0.9999 sample 2.693 ms/op
Compare.loomSemaphore:p1.00 sample 42.992 ms/op
Compare.reactive sample 723234 0.041 ± 0.001 ms/op
Compare.reactive:p0.00 sample 0.001 ms/op
Compare.reactive:p0.50 sample 0.037 ms/op
Compare.reactive:p0.90 sample 0.069 ms/op
Compare.reactive:p0.95 sample 0.082 ms/op
Compare.reactive:p0.99 sample 0.127 ms/op
Compare.reactive:p0.999 sample 0.213 ms/op
Compare.reactive:p0.9999 sample 1.148 ms/op
Compare.reactive:p1.00 sample 3.375 ms/op
Compare.kotlinSemaphore ss 5 0.023 ± 0.008 ms/op
Compare.loomSemaphore ss 5 0.068 ± 0.098 ms/op
Compare.reactive ss 5 0.252 ± 0.156 ms/op
@mingyang91
Copy link
Author

mingyang91 commented Dec 22, 2023

$ sysctl machdep.cpu
machdep.cpu.cores_per_package: 12
machdep.cpu.core_count: 12
machdep.cpu.logical_per_package: 12
machdep.cpu.thread_count: 12
machdep.cpu.brand_string: Apple M2 Max

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment