4 ms·
Looks misleading to me. Scala code spawns real threads while Go code uses go routines. If we want to compare apple to apples, we should use thread pool shared
by jakozaur 11y ago
Looks misleading to me. Scala code spawns real threads while Go code uses go routines.
If we want to compare apple to apples, we should use thread pool shared across Scala actors:
http://stackoverflow.com/a/1597942/341181 http://stackoverflow.com/a/1597942/341181
Just add 7 lines of code and Scala should get at least 10x faster.
- atemerev 11y agoAkka actors are not "real" threads, Akka scheduler runs them through available resources.
- merb 11y agoStill why didn't you did that: import scala.concurrent.duration.Duration import scala.concurrent.{Await, Future} import scala.concurrent.ExecutionContext.Implicits.global object FutureGen { def caller(num: Int, size: Int, div: Int): Future[Long] = { if (size == 1) { Future.successful(num.toLong) } else { val futures = for (i <- 0 until div) yield caller(num + i * (size / div), size / div, div) Future.sequence(futures).map(_.sum) } } } object Root extends App { // Warmup Await.result(FutureGen.caller(0, 1000000, 10), Duration.Inf) val startTime = System.currentTimeMillis() val x: Long = Await.result(FutureGen.caller(0, 1000000, 10), Duration.Inf) val diffMs = System.currentTimeMillis() - startTime println(s"Result: $x in $diffMs ms.") } This would give Scala: 499ms and Go: 436ms which is pretty neat, since go actually has no type system. (And I'm using the global execution context, which could also be changed) Currently your akka version is slow, since it's creating a new class on every call, so you would have like a dozen more methods to dispatch than my version.
- atemerev 11y agoCould you please open a pull request? Initially, I wanted to compare Akka actors with Erlang actors; perhaps I am unfair to plain old Scala.
- yankoff 11y agoThat's not the same. You are just creating a bunch of completed futures. Your code basically is just summing numbers up in a recursion here. Which is not what OP is trying to benchmark.
- merb 11y agoactually Future.sequence() will run dispatched. it would just make no sense to run the single number concurrently, as the go version won't do this, too. Future.sequence uses the global Executer. sum := 0 for i := 0; i < div; i++ { sub_num := num + i * (size / div) go skynet(rc, sub_num, size / div, div) } This is the go version and only the inside will run on a thread so I made a fair comparsion P.S: The go version will actually run single threaded when you are having GOMAXPROCS=1.
- yankoff 11y agoGo example seems off too from what the author intentions were. As for the dispatcher, I don't believe it will actually give any resource to a future that is already complete? OP wanted to have messages going through 1M actors, so there would be a moment when each actor gets a thread from a thread pool.
- merb 11y agoHowever it makes a difference if I create 1M actors and dispatch them via reflection or if I create some of them and passing results back and forth. actually goroutines would use static dispatching and don't have a lot of overhead. however a scala actor is totally different than any goroutines or erlang actors, they are keeping a lot of state. a promise/future is actually a little bit better in this kind of sense, still the jvm version will actually (even when optimized) use way more memory.
- sirclueless 11y agoThis is a silly argument. If I read you right, you are saying that a goroutine is closer to a promise/future than a Scala actor in terms of resources used, and therefore it's OK to use futures instead of actors in the Scala code and compare them that way. That betrays the whole benchmark. The basic point of the benchmark is to answer the question, "How expensive is it to create and run 1,111,111 actors in various languages?" You can't make a manual optimization that causes only 111,111 actors to be created and then say that it's a better comparison.
- wizzard0 11y agoBTW, there's a merged PR which makes Akka a lot faster; can someone measure that on OS X (MB Air or MB'2015) ?
- KirinDave 11y agoJust gonna put this out there: Scala is full of these scenarios where very small changes to the code have disproportionately large changes to the outcome. It's one of the reasons I'm really not a fan of the language. There are so many features that are mentioned in the literature and lore that you have to learn to not use, for fear of pervasive performance penalties. This is a great example. I've done a lot of Scala and o found the original version very obvious to read, but only experience tells me why the compiler can't make it efficient. Your version is not really worse in any way, but I think it's fair to say that it shouldn't be obvious to everyone why one is suboptimal at first glance.
- merb 11y agoeven if your downvoted. I think what you wrote is somehow true. it's really hard to optimize. but I don't think that Scala is the only language which has this downside. Also you could write really really awful code with scala.
- revelation 11y agoYes, if we make all the implementations do the same thing then we should expect the same results! The point is exactly to compare different implementations of the same concept. That's always the point in performance comparisons!
- farresito 11y agoThe parent comment is precisely saying that they don't all implement the exact same concept. Also, different runtimes will give different results, even if the concept is exactly the same.
- emergentcypher 11y agoSimilarly the Haskell and Erlang are using lightweight threading.