8 ms·
Scaling Scala vs Java
- js4all 13y agoThe title is a bit misleading. The blog post is about async calls in Java vs Scala using promises. Good read though.
- coolsunglasses 13y agoThis blog post is not great. It's also not about scaling at all. For one thing, a promises based async implementation is not incredibly helpful when you have a strictly one-after-another ordering of data dependencies. In the interest of comparison, however, I decided to translate the example code to the equivalent synchronous and asynchronous Clojure code. https://www.refheap.com/20640 https://www.refheap.com/20640 Things to note: Instead of being forced to use a compiler-assisted construct, promises on Clojure get dereferenced. Dereferencing is the same operation used to get the value of agents, atoms, and refs as well. Deref'ing (@) a promise over and over is totally okay. Using promises doesn't make the Scala solution meaningfully or usefully asynchronous unless the handler is yielding its thread while blocking on I/O.
- noelwelsh 13y agoI don't understand much of what you've written. Perhaps you can elaborate? Specifically: > It's also not about scaling at all. It's about handling many simultaneous connections. How is this not a specific type of scaling, and one that is relevant to many web sites? > a promises based async implementation is not incredibly helpful when you have a strictly one-after-another ordering of data dependencies. What does this mean beyond the fact that data dependencies limit parallelism? > Instead of being forced to use a compiler-assisted construct For comprehensions in Scala are syntax for the flatMap and map functions. You're not forced to use them, and for comprehensions work with any monad. > Deref'ing (@) a promise over and over is totally okay. Mapping a promise (the Scala equivalent) over and over is totally ok. > Using promises doesn't make the Scala solution meaningfully or usefully asynchronous unless the handler is yielding its thread while blocking on I/O. What does the IO model of the JVM have to do with Scala futures? Blocking IO operations are blocking, whatever language you use. There are three ways around this: 1. Use nonblocking IO 2. Use bytecode manipulation to transform blocking to nonblocking IO 3. Use a separate thread pool for blocking IO operations. 1 and 3 are the typical solutions in Scala.
- bad_user 13y ago> a promises based async implementation is not incredibly helpful when you have a strictly one-after-another ordering of data dependencies I don't understand what you mean. Of course it's helpful. memcached.get[String]("someKey") flatMap { case Some(value) => Future.successful(value) case None => database.query(...).flatMap { value => memcached.set("someKey", value, 10.minutes) } } The above fetches a key from memcached and in case it doesn't exist, it fetches it from the database and once that's done, it sets the value in memcached and once that's done the processing is done and thus you can continue with other things. If the clients are non-blocking, than that's totally asynchronous and scalable. In Clojure you don't see this because in Clojure people don't work with Monads. > Using promises doesn't make the Scala solution meaningfully or usefully asynchronous unless the handler is yielding its thread while blocking on I/O. The idea of Futures is not to use blocking I/O, but rather to either: 1) use non-blocking I/O, or 2) delegate the blocking I/O call to some sort of actor, then continue the execution once that's done Both are possible and quite easy.
- coolsunglasses 13y agoMonads are used in Clojure, just not for this particular use-case because it's unnecessary the majority of the time. A good example of monad (and macros) use would be: http://github.com/clojure/core.async http://github.com/clojure/core.async
- jondot 13y agoEvery now and then comes such an article and nudges me towards Scala again. It can really be an elegant and succinct language that can be all-encompassing. But although I have a production running Scala project, I cringe every time I have to work with Scala just because of the tooling. It's sad to see that SBT is cryptic and IDEs are slow and misleading. When I work on the JVM I prefer Clojure. I think lein makes an exemplary development, build, and dependency management tool. I wish Scala had that.
- ShardPhoenix 13y agoIntellij IDEA isn't so bad as an IDE (it's faster and less buggy than the Eclipse Scala plugin last time I checked), but SBT is utterly horrible. It's so awful I'd literally strongly prefer to use Ant (ie clunky scripting in XML) instead.
- TelmoMenezes 13y agoYup I second that. Intellij IDEA is currently very good with Scala, especially if one avoids SBT. I use it with Maven and everything works smoothly in a project with several sub-projects and various external dependencies (most to Java libraries). I suspect the awfulness of SBT is causing a lot of harm to Scala adoption.
- jgrowl 13y agoJetBrains has a nightly build out for their sbt plugin. It is not perfect yet but it has worked very well for me. http://blog.jetbrains.com/scala/2013/07/17/sbt-plugin-nightly-builds/ http://blog.jetbrains.com/scala/2013/07/17/sbt-plugin-nightl...
- _random_ 13y agoThis always makes me laugh! "Look guys we invented this new functional language - it's awesome" - well cool, now go back and make a decent IDE and tools for it.
- grogs 13y ago
- willvarfar 13y agoI'm a bit surprised because all my big Java servers have used Netty and are fully asynchronous. I didn't realise there's any big load of synchronous Java servers out there.
- jbrechtel 13y agoThe servers in this example were configured to be asynchronous. The clients were not. You may still be using asynchronous clients in your code but James's argument is that Java developers don't tend to do this because it requires a lot of boilerplate. Scala developers do this because it's very low syntatic overhead and frameworks+libraries embrace it.
- brown9-2 13y agoDevelopers who don't do something that would give them incredible performance and resilience because "it requires a lot of boilerplate" are bad developers.
- jebblue 13y agoNot necessarily, more code means more maintenance which translates to more cost. Adding new features requires more research, more work, more time, more cost. Fixing anything requiring a patch after going production with a new feature would likely be more expensive. Testing tools have to be verified to work with the additional code. This all increases costs which might be OK for some organizations and not so much for others.
- brown9-2 13y agoThat's a different argument though than just "it's more code so I won't do it". If we are discussing performance then the assumption is you have a performance problem you need to fix.
- willvarfar 13y agoTo be clear, my servers are clients of each other and all is asynchronous.
- abalone 13y agoThis comparison is extremely flawed. He is not comparing Scala vs Java. He's comparing Play Framework (async i/o) vs. a Servlet that doesn't use async i/o. He admits later that he purposefully handicapped the Java version. His reason is, he claims that Java's Promise pattern is so hard to program that "Java developers don't do that." Which.. wow. His evidence: he's written a lot of Java apps and he's personally never used it. And so he just switches off async i/o for Java. We all know Java has more boilerplate. The Promise pattern is 2 lines of boilerplate code per call, much like an event handler. To go from that to claiming "Java developers don't do" Promise is a huge, unsupported leap. Also you'd get the impression from his writing that Play Framework is only available for Scala.. but there's a Java API too.
- _random_ 13y agoWhy would a mostly similar language on the same runtime even help you scale that much? Surely it's about frameworks and technologies!
- room271 13y agoThe author is very clear that you can scale Java and Scala in the same ways. But doing this in Scala is much more idiomatic and concise.
- anuraj 13y agoIn the past few months, I have found the relative simplicity of vert.x trump play where ever an asynchronous framework needs to be used. And for everything else, there is the Servlet API.
- bad_user 13y agoFirst of all James Roper is one of the main engineers working on the Play Framework. You're quick to jump to conclusions. The "Promise pattern" is extremely awful for Java. Yes, Play does allow Java developers to do Async I/O by means of Futures/Promises. That doesn't make it any less awful and a quick search on Play's mailing list should highlight it. The reason for it is because working with Future/Promise instances involves a lot of calls to map() and flatMap(). In comparison to java.util.concurrent.Future (which sucks), these Futures are non-blocking and can be processed and transformed without doing a .get() ... We aren't talking about one or two calls, but rather about chains of calls. Scala is a language designed for this, it even has monad comprehensions and an upcoming library that should bring C#'s async [1] Iteratees are also one of the coolest notions for dealing with streams of data that ever came out of the FP world. And if in Java you can sort of limp around when it comes to simple Future/Promise objects, well Iteratees are in a different league [2] [3] The Play developers did an extremely awesome job by exposing a clean Java API. But some things are sorely missing, as there's no way to expose them in Java cleanly, which is why the internals of Play's server are written in Scala. Also, it does make sense to compare frameworks in language comparisons. For example you can't compare C# versus Java for web development, without comparing the frameworks themselves. If Play also allows you to use Java, that's only testament to the awesomeness of Scala, of the JVM and of Play's developers. [1] https://github.com/scala/async https://github.com/scala/async [2] http://mandubian.com/2012/08/27/understanding-play2-iteratees-for-normal-humans/ http://mandubian.com/2012/08/27/understanding-play2-iteratee... [3] http://www.playframework.com/documentation/2.2.x/Iteratees http://www.playframework.com/documentation/2.2.x/Iteratees
- pron 13y agoWell, it's a good thing we've got Java lightweight threads[1]. They let you write synchronous, blocking, simple code, which it transforms to asynchronous calls. It gives you this "Scala scalability" to Java (or any JVM language) without wrapping your head around functional constructs. Scalaists can think of it as an async macro that works for all JVM languages, and can span a whole call-stack rather than just a single expression. [1]: https://github.com/puniverse/quasar https://github.com/puniverse/quasar
- danieldk 13y agoI played a bit with Quasar a week ago. I really liked how simple it is to wrap existing async calls (with callbacks) using FiberAsync and use them in synchronous code. It's still a bit to early for me to migrate from Akka. But thanks for the great work you are doing!
- voidlogic 13y agoI dislike how the Java Promises and the Scala code unnecessarily hide the reality of the computation from the developer, take a Go version as counterpoint: func stockForProdsTO(uid int, timeout time.Duration) (*Stock, error) { stockCh := make(chan *Stock, 1) go func() { orders := ordersForUser(userById(uid).email) stockCh <- stockForProds(prodsForOrders(orders)) }() select { case result := <-stockCh: return result, nil case <-time.After(timeout): return nil, errors.New("Could not get stock for product before timeout.") } }
- huntc 13y agoIn fairness to James, I think the comparison he's making is in regard to the idiosyncrasies of developers, and that Java developers tend more often than not to use synchronous blocking calls. It is entirely possible to perform async IO in Java of course, but James's point is that being async is a more natural state when using Scala.