Hacker News new | past | comments | ask | show | jobs | submit login
Quasar and Akka – a Comparison (paralleluniverse.co)
49 points by circlespainter on May 21, 2015 | hide | past | favorite | 44 comments



Seems like a very one sided comparison. Most other posts from paralleluniverse have also come off this way.


An early giveaway is the 5 paragraphs (325 words in total) introducing Quasar, versus the single paragraph (69 words) about Akka.


Plus, the ParallelUniverse guy keeps trying to spread FUD about Scala in pretty much every Java/Scala/whatever thread.


Anytime I see "Not needed" instead of "No" in a feature comparison chart, I am inclined to just stop reading.


In this case, as in many others, "not needed" means that one abstraction that is present makes other abstractions unnecessary. For example, if blocking is free, a non-blocking API is not needed, or if actor receives are selective, then message stashing is not needed. Saying "no" would imply that the functionality is missing, when in fact it is present only doesn't require a separate abstraction.


Here are two examples of this in action: http://imgur.com/a/YaQyn#1


It's one sided because it's written by the guys who wrote Quasar. Anytime you see a comparison of "code I wrote vs this other library..." you aren't going to get an unbiased report.


They have conveniently omitted the fact of existence of Akka.NET which gives C#, F#, .NET support.

This is not a minor feature.

http://getakka.net


True, although it's a community project and not part of the main Akka project AFAIK. Worth mentioning though, thanks for pointing out.


I don't agree but can you expand? Which parts are one-sided in your opinion and which other posts?


Certainly.

I think it starts off with your claim that Quasar is easy to integrate with existing Java libraries. I find that claim to be untrue since any library it's used with needs to be retrofitted/wrapped to make it work with Quasar. If that isn't the case I don't understand why Comstat exists.

The article makes it seem like Akka cannot be used from Kotlin. I think that's disingenuous, given that Akka has a Java API there is absolutely no reason to not be able to use it from Kotlin, or Groovy. I'm unsure if Quasar can't be used from Scala because of the Bytecode manipulation that you're doing being incompatible with the Bytecode that the Scala compiler is putting out.

I don't understand the part about "non-standard DSL" being used to describe the method of composing futures in Akka. Seems weird to call a DSL "non-standard". I'm also not seeing a DSL in the accompanying code.

Then there are the claims that Quasar being able to run inside a Servlet container is really a huge advantage. No explanation at all is given for that assertion. As far as I'm aware it was not a goal of the Play framework to be Servlet compatible. It's a framework that provides a HTTP server, I don't see this as fundamentally different than Node or Go which also do this. Python and Ruby need application servers like uWSGI and Unicorn, I don't see why that's a good thing but the article claims that running under a JavaEE Servlet container is a good thing as if it's an axiom.

I'm excited about continuations on the JVM. Lightweight threading is something I'd love to have. I used to work on a Actor based language that compiled to the JVM (a very object-oriented actor language). The lack of lightweight threads was a real issue for that system.

However posts come off as unreasonable because of the tone.

Disclosure - I've not worked withQuasar or Comstat just yet so I can't talk to their technical abilities.


> any library it's used with needs to be retrofitted/wrapped to make it work with Quasar.

True, but 1/ to see how easy it can be to integrate a pre-existing library with Quasar, just have a look at the OkHttp integration in Comsat's master and at this post http://blog.paralleluniverse.co/2014/08/12/noasync/ and 2/ the integrations provide an API identical to the original ones, not new ones, which makes the transition (and the opt-out) easy. Further so considering that fibers have API and usage practically identical to regular threads. So there's no API proliferation when integrating Quasar and the integration implementation itself can amount to just few lines of code.

> The article makes it seem like Akka cannot be used from Kotlin

Akka can surely be used from Kotlin (or even Clojure probably, for that matter), yet it lacks an idiomatic wrapper for it, which Quasar is starting to provide (and has offered for quite some time now for Clojure). Both Kotlin and Clojure are good at using existing Java APIs conveniently but, especially in Clojure's case perhaps, I think the lack of an idiomatic wrapper would be felt as an important minus, especially considering how concise and lean Clojure idiomatic APIs usually are.

> I'm unsure if Quasar can't be used from Scala because of the Bytecode manipulation that you're doing being incompatible with the Bytecode that the Scala compiler is putting out.

Quasar's bytecode manipulation amounts to user stack management in order to schedule continuation tasks and generally plays well with other instrumentation agents. Language integration could be very easy (f.e. Kotlin) or less easy (f.e. Scala) depending on the language implementation but I think it is entirely possible to build an integration module for Scala, only it seems to require some effort and so far there have been other priorities on our side.

> I don't understand the part about "non-standard DSL" being used to describe the method of composing futures in Akka. I'm also not seeing a DSL in the accompanying code.

The Future API itself and composition operators (e.g. "Future.sequence(futureSentiments)") are a new async/monadic concurrency DSL meant to work around Java threads being heavyweights. But why adopting a different API and programming model when the pre-existing thread abstraction can simply be made more efficient? I think API proliferation and expansion in general is not a good thing, and more so if it's only meant to work around implementation problems.

> Then there are the claims that Quasar being able to run inside a Servlet container is really a huge advantage.

I'm not advocating for Servlet containers, on the opposite I personally think standalone app deployments are better. But there are a lot of companies with substantial Servlet infrastructure out there and accompanying IT/DevOps processes and skills that can't always afford (or not quickly) a shift to other deployment practices (and I have direct experience about that). So, in the spirit of playing nicely with what is already there, which is also based on standards (even if not always most enjoyable ones), I think it is definitely an advantage to offer such an option.


Saying Quasar supports Kotlin/Clojure as though Akka does not (considering both languages interop with Java) is unfair. There is a difference between bytecode manipulation making alternative JVM languages impossible vs just not having a language-idiomatic wrapper.

There a few other parts I take slight umbrage with (e.g. pretending Akka is heavyweight, has deployment rules, incomplete integration information, etc) but overall a nice informative comparison if a tad biased feeling.


Some of it is definitely misleading. Saying that Akka forces you into a logging library when it can be used with log4j, logback, provides a bridge with slf4j, etc, is just being uncharitable. As is claiming that "commercial tools" are needed for monitoring when JMX can be used just as with Quasar. Same with labeling Akka's clustering support as "experimental". Akka dropped that status from the clustering module a while ago (I had it in production for over a year).

I get that it's marketing material so it's going to be biased but I can't help but feel that one too many liberties were taken in making Quasar look good.


This is most evident in the conclusion: "Akka [...] is a totalizing choice", "blocking is free", "Akka [...] the way to go if [...] you have embraced Scala", "Akka [...] betting on a framework and sticking with it [...] high rewrite price", on and on. In retrospect I would remove "a tad" from the last sentence of my original post.


Can you expand on why you think these statements are not correct? I think they are thoroughly explained in the post.


* Akka is not a totalizing choice, it's just a concurrency mechanism. Many people to not bury logic in there but in traits or other places handling normal futures. That's like saying if you use threads, it's a totalizing choice regardless of where the majority of your code resides.

* "blocking is free" is contradicted right up earlier in the post with "highlights the additional cost of the real lightweight threads in Quasar"

* I will admit, between these two choices, you must choose Akka if you embrace Scala. But the inverse is not true.

* I don't believe it's a high rewrite price any more than any other library is. Do I pay a high rewrite price for using any other abstraction? I mean I just have functions that return futures, but because I composed them with Akka I can't rewrite it?

In general I think it's unfair to make assumptions or opinions here. To compare objectively is one thing, but to say something is a choice one way, requires you code one way, etc is invalid.


> Akka is not a totalizing choice, it's just a concurrency mechanism.

... that doesn't play nice with any other Java (or Clojure) concurrency mechanism.

> "blocking is free" is contradicted right up earlier in the post with "highlights the additional cost of the real lightweight threads in Quasar"

Well, very nearly free, and the cost will drop further.

> I mean I just have functions that return futures, but because I composed them with Akka I can't rewrite it?

Pretty much. Java code doesn't work that way, and certainly doesn't integrate with Scala futures. Also, you commit to using non-standard APIs in much of your application. With Quasar you'll likely write the REST endpoint in standard JAX-RS, and run it on top of Tomcat or Jetty or JBoss. So Akka is a library that 1/ encompasses many facets of your application, 2/ uses non-standard APIs everywhere and 3/ uses non-idomatic APIs that are very hard to compose with other Java libraries.

> to say something is a choice one way, requires you code one way, etc is invalid.

Akka does require you to write asynchronous code throughout the entire call-stack.


> [Akka] doesn't play nice with any other Java (or Clojure) concurrency mechanism

I've been using Akka in combination with Scala's Futures, with Java 8's CompletableFutures, with Rx Observables, with in-house asynchronous queues and I can't see how Akka doesn't play nice. With the introduction of the reactive streams protocol, piping streams of events between multiple libraries becomes really easy as well.

> Java code doesn't work that way, and certainly doesn't integrate with Scala futures.

Akka exposes a Future interface for Java, however I don't see the problem with working with Java's CompletableFuture or whatever is in Guava. I've done that, it's quite OK. Also, along with Scala 2.12 (now in milestone), Futures from Scala will be usable straight from Java 8.

> With Quasar you'll likely write the REST endpoint in standard JAX-RS, and run it on top of Tomcat or Jetty or JBoss.

You can do that with Akka as well, I've done that, I don't see the problem there.

> Akka does require you to write asynchronous code throughout the entire call-stack.

I've worked on an RTB system processing over 30000 transactions per second, I'm working now on a system processing real-time events coming from industrial machines. I've been using Akka where it makes sense and while I only played with Quasar, I do have a lot of experience with Gevent and Eventlet in Python and the bit about "synchronous" and "blocking" code being easier (while cheating by patching connections) is bullshit, for one because sometimes it doesn't work creating more problems than it solves and because it doesn't simplify anything of importance. People should write asynchronous code throughout the entire call-stack, it's doable and fun with the right tools ;-)

I expanded a little for the why in another comment: https://news.ycombinator.com/item?id=9585424


> You can do that with Akka as well, I've done that, I don't see the problem there.

The problem is that your (JAX-RS) endpoint will then not scale as much as your business logic.

> People should write asynchronous code throughout the entire call-stack

Ah, but why? Forget for a second about Quasar and its current implementation. Why on god's green earth should people ever consider writing asynchronous code? Correct me if I'm wrong, but the only answer to that is "to avoid blocking threads, which is expensive". If you had a way to make blocking threads inexpensive and therefore not have to write asynchronous code, wouldn't that be better (even if you think async code is not hard)?


> I've been using Akka in combination with Scala's Futures, with Java 8's CompletableFutures, with Rx Observables, with in-house asynchronous queues and I can't see how Akka doesn't play nice.

Quasar doesn't introduce an async programming framework to work around threads inefficiencies, it simply gives you more efficient threads.

> You can do that [write REST endpoint] with Akka as well, I've done that, I don't see the problem there.

Without Quasar, for your services you can either use normal JAX-RS, which is based on Java's heavyweight threads, or Play (or Spray) which is non-standard and async. With Quasar instead you can use standard JAX-RS with regular blocking code, but running on lightweight threads.

> the bit about "synchronous" and "blocking" code being easier (while cheating by patching connections) is bullshit [...] People should write asynchronous code throughout the entire call-stack [...]

Probably I don't understand because I don't know much about Gevent and Eventlet but for info about Quasar I/O pls. refer to my other comment: https://news.ycombinator.com/item?id=9585737. As for async being the way to go, I don't agree and the many discussions about async code problems tell me I'm not alone in that.


Actually the statement about logging is a bit different and says that Akka offers an additional logging API, which is correct I believe, and I think this is unnecessary since a pre-existing one could be used. As for clustering it's probably just an error in the table, thanks for pointing it out, I'll fix it. As for JMX, I didn't find info about non-cluster metrics, although there seem to be some 3rd-party projects to get more, but maybe I missed something. Do you have pointers?


Actually bytecode manipulation doesn't make JVM alternative languages impossible, on the opposite Quasar allows them to be easily integrated and investigation/work is ongoing to avoid even having to do that. Plus, depending on the language implementation, in some cases integration is just not needed.

Of course you can use Akka with Kotlin (and Clojure, although not sure how convenient that would be) but there's no idiomatic API (yet?), while Quasar offers them.


I'm really looking forward to when suspendable annotations are no longer needed, so there isn't any special work that needs to be done to support (for example) Scala.


We're working on it, but it might require Java 9.


Quasar is going the right direction - writing synchronous code is better - the code is simpler and cleaner. There is no inherent performance penalty in synchronous approach, it's just the runtime systems of many popular languages make it so - statically allocated stack, and some penalty of context switch via system call. In addition to the languages mentioned in the article (Go, Clojure core.async, Erlang), Gambit Scheme deserves to be mentioned, winch can spawn millions of lightweight (green) threads. Also there was Stackless Python.

BTW, no need to describe the implementation in terms of continuations. It's just enough (I think) to allocate function activation records on heap instead of statically allocated stack. (AFAIK continuations are also implemented similarly, although what I've read about Go, their call stack management is something more complex)

Also, I think the "actor model" is not the final solution for scalable distributed programming, it's just some initial, and IMHO pretty clumsy step. We will have better approaches soon.


I feel like Actor is a quantum leap ahead of all the previous and current paradigms, like Promise and Future and Async. What do you think makes it clumsy and why do you think we have something better in store?


The problem, I suspect, is that there isn't really one formal "actor" model that everyone agrees on. People have used it to describe formal models like CSP and linear logic, practical systems like the Erlang VM and Go's green threading implementation, and capability-based systems like the (provably secure) SEL4; these are not the same thing. And, not to pick on you specifically, this is exacerbated by confusingly referring to "promises, futures, and async" as "paradigms." Promises and futures are for the most part identical, and I don't see how you can meaningfully call them "paradigms"--they're just APIs. "Async" (async what?) is maybe abstract enough that I'd be willing to call it a "paradigm," but I don't see how actors don't also fall into that category.


could you point to a place where anyone's said that Go, or any other CSP system, are Actor systems? That would be interesting to see.

Promises and futures are not actually identical; and they're paradigms, because they are concepts shared across a large number of different languages. 'Async' is the P in CSP, as in C# (called 'async'), and as in ES7 (https://github.com/lukehoban/ecmascript-asyncawait). Hope this helps you.


Chicken Scheme also has lightweight threads (doesn't have native threads though).

It does not make any performance claims about them, as far as I know.


Just wanted to comment on the "Blocking vs. Non-Blocking" nature of the different actor implementions. The article here says

A reason for choosing the asynchronous, callback-based approach has been that blocking plain OS threads entails significant overhead (as does the mere existence of many threads), which can be avoided with a non-blocking API. However, because Quasar – just like Erlang and Go – has true lightweight threads, blocking carries virtually no overhead

In my opinion the difference is much then whether an OS thread is blocked or not. Being able to make synchronous-looking (but not-thread-blocking) calls inside Actors still will block the Actor for other incoming messages for that amount of time. So you have states were the Actor is unresponsive - and with the right amount of dependencies between Actors you can deadlock.

A Actor which doesn't use any blocking calls internally will be more responsive and less prone to deadlock. But of course - you have to model more states explicetly. E.g. if I have an Actor routine that's like

  while true {
    var msg = await mailbox.Get();
    if (msg is XYZ) {
      var result = await doSthAsync()
      updateState(result)
    }
  }
and would like to transform that into a completly nonblocking implementation then I would need to model an extra state and probably handle messages differently in the timeframe between doSthAsync() was sent and the result is received.

This can be a good thing (you can be more responsive and all states are explicit) and also a bad thing (more verbose code).

Important is also that with the blocked Actor one get some kind of backpressure strategy for free. Whereas with the nonblocked Actor one has to handle that also explicitly.

I tried both concepts in my recent work, the blocked actor mainly with F#'s mailbox processor and the nonblocked with my own implementation and personally favor the second version now. I find it quite useful to think about and model Actors as state machines and beeing able to handle all kinds of state transitions explicitly. It also made deadlock prevention easier.

Nevertheless I'm seriously impressed about the capabilities of Quasar and Pulsar.


I'll only add that Quasar offers several types of "send" and "receive" operations: blocking indefintely, with timeout and even "try" variants that will not block at all, as well as several mailbox types, so the developer can regulate queues, responsivity (and backpressure) as desired.


How much does the fact you have non blocking green threads matters when you have a cluster of 100 machines? Yes, internally in each machine there are less kernel threads and less overhead, but If an actor on one machine sends a message to an actor in another, does it matter if it's a jvm thread or a fiber?


If you want regular code and not async, then yes, it matters: if you have a lot of OS thread-based actors performing blocking network "send"s as part of their regular control flow, each of them blocks an OS thread and you'll run out of resources soon. If those actors are backed by lightweight threads instead, which are very frugal, basically you are only limited by the network stack.


My thought is that always the network is the bigger bottleneck. But I guess it depends on the data / OS etc.


The article is full of incorrect statements and biased opinions, I stopped reading at some point, because even though I think Quasar is really interesting, this article has been a turn off. Some things that bothered me ...

Akka follows the Erlang actor model pretty faithfully and what you do in the actor model is that you model state machines. In Scala you can also work with scala-async [1], which is basically what Quasar does, but that is not enough because calling a function and getting back some future result is only a really simple use-case, whereas in practice you get streams of messages and the communication is a bidirectional ping-pong.

So you work a lot with context become/unbecome [2], which is very much like what you'd do in Erlang for evolving state. This is because modeling a communication protocol requires multiple stages and a constant dialog with the other side. Even in a simple producer/consumers relationship you need back-pressure. Pretending that the communication is somehow synchronous is not going to fix the non-deterministic nature of this process and the logic will end up looking mostly the same. This is because it's not the asynchronicity that bites you ;-)

Quasar cannot make blocking I/O to not block threads, although it's clearly stated in the article, but that's just wrong. You can indeed patch connections to work with Quasar's fibers, working much like how you patch sockets in Python with gevent, so you can create your own JDBC data-source that plays nice, but that's not the same thing.

This really means that your pieces of I/O logic are still separated into blocking and non-blocking (red versus blue) and I'd rather see which is which by seeing `Future[T]` or `Observable[T]` in my function signatures. Therefore I disagree that Quasar code is more readable, but at least I'm willing to admit that YMMV.

Also, that Quasar actor given as an example has nothing to do with the actor model. This is because in the actor model the actors are untyped. If you type your actors, then you're not talking about the actor model anymore and you'd be better off with another computational model. At the moment it is completely futile to try to type state machines that work in a non-deterministic highly concurrent environment. And if you go through the effort of typing those actors, then you have to at least recognize that actors can communicate with multiple other actors at the same time and thus expose multiple interfaces. And then you can say that at the very least your typing says something more useful than Object or String.

I could write more, but I got tired.

[1] https://github.com/scala/async

[2] http://doc.akka.io/docs/akka/snapshot/scala/actors.html#beco...


In Akka an actor is basically a message handler; I personally think that being able to use regular control flow constructs is an easier way to model state machines than swapping around message handlers.

scala-async looks more like core.async's go to me, i.e. it macro-transforms blocks of code that include special constructs into some continuation-passing style. Quasar implements lightweight threads on the JVM (via bytecode instrumentation, which is a language-independent mechanism), and this is a different thing: no special constructs are needed, you just write regular blocking code (only in lightweight threads, that have basically the same interface and usage as regular Java threads) using normal method calls and control flow constructs. Quasar will take care of blocking/resuming/scheduling efficiently.

As for I/O, Quasar integrations allow lots of fibers to make blocking calls _without_ as many OS threads blocking. The underlying implementation mechanism is often to tap into an async API, suspending fibers when an async call is started and installing an handler that will resume them when the async call completes. Quasar includes such an integration with Java NIO for files and sockets and more are available in Comsat (e.g. with servlet async, async HTTP clients etc.).

I agree about typed actors not being too helpful in dynamic, complex and highly concurrent environments, but in some situations (e.g. transient one-receive actors) they can help keeping communication in check more statically. Of course one can just avoid using types if not needed and Quasar behavioural actors are actually untyped.


> This is because it's not the asynchronicity that bites you

But it's certainly what makes your code much harder to read and write (certainly when not using Scala), and it is exactly what colors your code in red and blue.

> This really means that your pieces of I/O logic are still separated into blocking and non-blocking (red versus blue)

But they're not. You can use the same wrapped JDBC data source, or the same lock in your threads and your fibers. There is no more "non-blocking", so it really does uncolor your code -- all code can run in a fiber or a thread. You can take the very same code and run it in a thread -- in which case a kernel thread will be blocked -- or a fiber -- in which case the fiber will be blocked -- and the only difference will be how many of those threads/fibers (Quasar calls them both "strands") you can have, which is exactly a heavyweight/lightweight choice.


If best things were winning we would all be using Mercurial and JS would be long dead. Popularity and endorsment decide.


By the way I'm the author of the post so feel free to get in touch, I'll be glad to answer any questions.


On GitHub, Akka has 14659 commits, 82 branches, 150 releases, and 188 contributors. Quasar has 1753 commits, 14 branches, 9 releases, and 7 contributors.

All other statistics are also massively in favor of Akka (just look at the numbers for this past week, or the number of contributors that are really active in both projects).

Akka is serious business software, that companies can safely rely on, without gambling their money. It is easy to use, performant, low risk, and has an incredible team of very capable developers who have been perfecting it for years. And "serious and safe" does not at all mean static: they constantly keep pushing the state of the art (I didn't see anything in the article about Akka Streams, Spark, the upcoming typed actors, any emphasis on the usefulness of message persistence, ...).

If you want to challenge the market leader, you will need more than biased reviews: you will need more people working on it, more activity, and real-life success stories.


I'm not affiliated with either horse in this race, but it would be good for you to explain exactly what about those repo statistics favors Akka. Seems like the numbers are larger, of course, but I'm aware of no relationship between any of those numbers and project quality. Or anything else, for that matter.


I am also not affiliated with either.

When you choose the backbone of your architecture, there are other things to consider, in addition to technical aspects. The numbers I mentioned give an indication of some of those aspects.

If I look at Quasar in GitHub, it seems to have only two developers who are really active: the same two people who are writing on this thread. Let’s say I adopt Quasar and base my architecture on it. What happens when these guys land a big project paying big money with a big client? Will they have time to fix issues? Will they have time to develop new features? Will the big client dictate the direction of new developments?

Look at Akka on the other side. They have people like Jonas Bonér, Viktor Klang, Roland Kuhn, Mathias Doenitz, etc. People who are not only amazing developers, but who are also thought leaders. These guys publish books on the subject, speak at conferences, conduct massive online training, and have industry recognition. And they are just the tip of the iceberg. They have a team of less-famous but equally amazing rock star delelopers working with them. Akka gets more solid as time progresses, not only technically but also in terms of market perception.

On which of the two horses would you place your bet?

Quasar may have its technical merits, but unless it comes up with a really compelling feature that gives it a sustainable advantage against Akka, it has no chance of winning.


You can add Akka.NET stats: 2,352 commits, 6 branches, 28 releases, 52 contributors.

https://github.com/akkadotnet/akka.net




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: