Skip to content

Instantly share code, notes, and snippets.

@anthonynsimon
Last active June 24, 2018 12:30
Show Gist options
  • Save anthonynsimon/a15841cac4efc20a22855819df953839 to your computer and use it in GitHub Desktop.
Save anthonynsimon/a15841cac4efc20a22855819df953839 to your computer and use it in GitHub Desktop.
Skynet benchmark
import kotlinx.coroutines.experimental.*
import kotlinx.coroutines.experimental.channels.Channel
import java.util.concurrent.atomic.AtomicLong
import kotlin.concurrent.thread
fun main(args: Array<String>) {
// bench("threads") { skynetThread(0, 1000000, 10) } // Out of Memory error
bench("sync") { skynetSync(0, 1000000, 10) }
bench("coroutines-async") { skynetCoroutinesAsync(0, 1000000, 10) }
bench("coroutines-launch") { skynetCoroutinesLaunch(0, 1000000, 10) }
bench("channels") { skynetChannels(0, 1000000, 10) }
}
fun bench(name: String, times: Int = 10, func: () -> Long) {
println("Running $name...")
repeat(times) {
val start = System.nanoTime()
val result = func()
val duration = (System.nanoTime() - start) / 1e6
println("result $name: ${result} took: ${duration} ms")
}
}
fun skynetSync(num: Int, size: Int, div: Int): Long {
if (size == 1) return num.toLong()
else return (0 until div)
.map { i -> skynetSync(num + i * (size / div), size / div, div) }
.sum()
}
fun skynetThread(num: Int, size: Int, div: Int): Long {
if (size == 1) return num.toLong()
val sum = AtomicLong()
repeat(10) { i ->
thread {
val childSum = skynetThread(num + i * (size / div), size / div, div)
sum.addAndGet(childSum)
}
}
return sum.get()
}
fun skynetCoroutinesAsync(num: Int, size: Int, div: Int): Long {
fun _child(num: Int, size: Int, div: Int): Deferred<Long> = async {
if (size == 1) num.toLong()
else {
val children = (0 until 10).map { i -> _child(num + i * (size / div), size / div, div) }
children.map { it.await() }.sum()
}
}
return runBlocking { _child(num, size, div).await() }
}
fun skynetCoroutinesLaunch(num: Int, size: Int, div: Int): Long {
val sum = AtomicLong()
fun _child(num: Int, size: Int, div: Int): Job = launch {
if (size == 1) sum.addAndGet(num.toLong())
else (0 until 10)
.map { i -> _child(num + i * (size / div), size / div, div) }
.forEach { it.join() }
}
return runBlocking {
_child(num, size, div).join()
sum.get()
}
}
fun skynetChannels(num: Int, size: Int, div: Int): Long {
val resultChan = Channel<Long>()
fun _child(num: Int, size: Int, div: Int, chan: Channel<Long>): Job = launch {
if (size == 1) chan.send(num.toLong())
else {
var sum = 0L
val sumChan = Channel<Long>()
repeat(10) { i ->
_child(num + i * (size / div), size / div, div, sumChan)
}
repeat(10) {
sum += sumChan.receive()
}
sumChan.close()
chan.send(sum)
}
}
return runBlocking {
_child(num, size, div, resultChan)
resultChan.receive()
}
}
import java.util.concurrent.Executors
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, ExecutionContext, Future}
object Main {
def main(args: Array[String]): Unit = {
implicit val ec = ExecutionContext.fromExecutor(Executors.newWorkStealingPool())
bench("sync") { skynetSync(0, 1000000, 10) }
bench("futures") { skynetFutures(0, 1000000, 10) }
// bench("actors") { skynetActors(0, 1000000, 10) }
}
def bench(name: String, times: Int = 10)(block: => Long) = {
println(s"Running $name...")
(0 until times).foreach { _ =>
val start = System.nanoTime()
val result = block
val duration = (System.nanoTime() - start) / 1e6
println(s"result $name: $result took: $duration ms")
}
}
def skynetSync(num: Int, size: Int, div: Int): Long = {
if (size == 1) num
else (0 until div).map(i => skynetSync(num + i*(size/div), size/div, div)).sum
}
def skynetFutures(num: Int, size: Int, div: Int)(implicit executionContext: ExecutionContext): Long = {
def _child(num: Int, size: Int, div: Int): Future[Long] = {
if (size == 1) Future.successful(num)
else Future.sequence((0 until div).map(i => _child(num + i * (size / div), size / div, div))).map(_.sum)
}
Await.result(_child(num, size, div), Duration.Inf)
}
// def skynetActors(num: Int, size: Int, div: Int)(implicit actorSystem: ActorSystem): Long = ???
}
==== Kotlin ====
Running sync...
result sync: 499999500000 took: 78.530253 ms
result sync: 499999500000 took: 46.281675 ms
result sync: 499999500000 took: 14.877077 ms
result sync: 499999500000 took: 13.812556 ms
result sync: 499999500000 took: 12.982618 ms
result sync: 499999500000 took: 14.750728 ms
result sync: 499999500000 took: 12.540582 ms
result sync: 499999500000 took: 14.040338 ms
result sync: 499999500000 took: 14.960383 ms
result sync: 499999500000 took: 32.027634 ms
Running coroutines-async...
result coroutines-async: 499999500000 took: 1693.764577 ms
result coroutines-async: 499999500000 took: 1442.738373 ms
result coroutines-async: 499999500000 took: 558.769895 ms
result coroutines-async: 499999500000 took: 468.704341 ms
result coroutines-async: 499999500000 took: 309.511122 ms
result coroutines-async: 499999500000 took: 295.281503 ms
result coroutines-async: 499999500000 took: 274.425134 ms
result coroutines-async: 499999500000 took: 237.899334 ms
result coroutines-async: 499999500000 took: 257.825042 ms
result coroutines-async: 499999500000 took: 322.748843 ms
Running coroutines-launch...
result coroutines-launch: 499999500000 took: 321.341801 ms
result coroutines-launch: 499999500000 took: 247.820448 ms
result coroutines-launch: 499999500000 took: 200.346479 ms
result coroutines-launch: 499999500000 took: 242.544458 ms
result coroutines-launch: 499999500000 took: 198.280846 ms
result coroutines-launch: 499999500000 took: 275.346196 ms
result coroutines-launch: 499999500000 took: 202.718254 ms
result coroutines-launch: 499999500000 took: 339.326855 ms
result coroutines-launch: 499999500000 took: 199.605175 ms
result coroutines-launch: 499999500000 took: 212.286115 ms
Running channels...
result channels: 499999500000 took: 848.969901 ms
result channels: 499999500000 took: 551.106903 ms
result channels: 499999500000 took: 379.826516 ms
result channels: 499999500000 took: 413.250208 ms
result channels: 499999500000 took: 474.846472 ms
result channels: 499999500000 took: 504.460687 ms
result channels: 499999500000 took: 386.361889 ms
result channels: 499999500000 took: 456.965036 ms
result channels: 499999500000 took: 597.235443 ms
result channels: 499999500000 took: 416.664959 ms
==== Scala ====
Running sync...
result sync: 499999500000 took: 138.729668 ms
result sync: 499999500000 took: 34.332871 ms
result sync: 499999500000 took: 35.911405 ms
result sync: 499999500000 took: 73.810535 ms
result sync: 499999500000 took: 33.670636 ms
result sync: 499999500000 took: 33.476382 ms
result sync: 499999500000 took: 59.939789 ms
result sync: 499999500000 took: 86.468402 ms
result sync: 499999500000 took: 33.078457 ms
result sync: 499999500000 took: 30.488075 ms
Running futures...
result futures: 499999500000 took: 1478.379823 ms
result futures: 499999500000 took: 274.371843 ms
result futures: 499999500000 took: 390.000957 ms
result futures: 499999500000 took: 247.929816 ms
result futures: 499999500000 took: 240.096408 ms
result futures: 499999500000 took: 219.66959 ms
result futures: 499999500000 took: 203.490966 ms
result futures: 499999500000 took: 223.054255 ms
result futures: 499999500000 took: 211.741709 ms
result futures: 499999500000 took: 212.549607 ms
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment