58 comments

[ 9.7 ms ] story [ 228 ms ] thread
I'm not sure node.js is faster than Java... My experience shows the contrary, but I switched to Node.js nonetheless. Node is fast... enough.

And socket.io justifies using Node :-)

Yea. This headline has to be troll bait. NodeJS is not faster than Java, and it's also not Concurrent. It is single threaded. It makes efficient use of that single thread with an event-oriented model.

That said, I tend to prefer building in NodeJS because it's fast enough for most (unanticipated) use cases.

There's a difference between concurrency and parallelism. Concurrency is about a programming model for doing multiple independent tasks while parallelism refers to doing them at the same time. For example with node, you can handle requests while waiting for an asynchronous io task like reading a file.

http://blog.golang.org/concurrency-is-not-parallelism

Parallelism is doing different parts of the same task at the same time. Concurrency is doing multiple, different tasks simultaneously. Single threaded, event oriented systems can appear to be concurrent. They can never be parallel.
Your operating system is concurrent even if it's single threaded.

Concurrency is about doing things in the same time period not necessarily at the exact same time.

That said, saying (concurrent) Node is faster than (nonconcurrent) Language X is several distinct levels of stupid.

If you introduce blocking into an application then to the user it slower, but in terms of computation it could still be faster by some magnitude.

It's like having C block on a network call while having in-browser Javascript concurrently move past it and declaring Javascript faster.

> Language X

Actually, comparing runtime/platform (Node) to language is completely pointless. Language is, well, only a language, it can't be "faster" or "slower" unless we're talking about coding speed. We have to compare implementations.

And even if we treat Java as a platform, contrary to Node it has ton of highly-varying implementations, so it's still pointless without careful clarifying what one compares. Or they may accidentally find out there's a Java variation with green threads somewhere that may break the whole "look, their ugly threads are slow and our event loops are fast" charm.

The article is just a pure load of non-sense. Highly flammable, though.

Node offers parallelism through load balanced processes. See cluster.
node.js could be concurrent. You just run multiple node.js processes and leverage the tried and true concurrency of the UNIX process model, which Erlang architecture is based on.
At first, I was ready to dismiss this article completely. However, this paragraph:

"While Java or Node or something else may win a benchmark, no server has the non-blocking ecosystem of Node.js today. Over 50k modules all written in the async style, ready to use. Countless code examples strewn about the web. Lessons and tutorials all using the async style. Debuggers, monitors, loggers, cluster managers, test frameworks and more all expecting your code to be non-blocking async."

is true.

Java has had all of the same async capabilities for many, many years, but nobody uses them because the blocking paradigm is simply easier.

That said, if true scalability is required, I'd suggest living with Akka and the cleaner actors paradigm. However, it's true that eventually you're going to run into the barrier that the vast majority of the java ecosystem is built on blocking io.

(That said, with Java 8, I think we have a real opportunity to change that. I think a parallel "lean java" ecosystem is coming.)

Re: "Java has had all of the same async capabilities for many, many years, but nobody uses them"

That's exaggeration.

Lots of Java libraries use async and concurrency. Java 7 has NIO.2 which is easy to use. There is also Netty; many projects build upon that.

I'm not here to say Java's ecosystem is richer or better; I'm just saying exaggeration is not useful.

Re: "the vast majority of the java ecosystem" I don't mean to sound dismissive, but lots of languages have code you probably don't want to use based on your preferences or needs. So? Don't use the vast majority of libraries. :) You probably don't anyway.

UPDATE: See also Akka and Clojure's concurrency for useful, popular approaches for the JVM.

I use akka for much if not all of my heavy lifting on the JVM. Admittedly, it's a little awkward sometimes, but if you make the right tasks non blocking (run it in a future), you would be surprised at the performance increase you can net.
> Over 50k modules all written in async style, ready to use

Actually, not true in "all" and "ready to use" parts.

I suspect there are enough libraries that, even while exposing supposedly-async API block under the hood. Or require careful handling.

Even core Node libraries are not throughly async. One obvious example is `crypto`, where only I/O stuff (accessing OS entropy pool) is async. Good luck generating a keypair in event loop.

> no server has the non-blocking ecosystem of Node.js today. Over 50k modules all written in the async style, ready to use.

I read it as -- "Node.js doesn't properly support isolated units of concurrency and thus due to being forced to write callbacks inside callbacks that call errbacks for everything, we now have over 50k modules full of callback chains and we call this a GoodThing(tm)".

I'll call you when you need me.
I don't think that's entirely fair. The standard callback model can easily be converted to a promise-based one with Q or a CSP channel-based one with ClojureScript's core.async or any number of other models.
It is but most of those module are not written like that.

For example Python's eventlet and gevent are based on greenlet. Greenlet is based underneath on large select/epoll/kqueue/poll loop. So there are callbacks for IO readiness there. However they manage to do some tricks to hide that away behind green threads at the user level. So a user can say: " authorize() ; check_database(); charge_credit_card(); update_database(); send_response()" logic properly for each request for example. Without having to split that logic into a chain of callbacks just because some of them might involve at some point making a socket call.

While I'd tend to agree, this may be a case of "worse is better."

In the java ecosystem, most of it assumes blocking IO. If you're trying to get out of this mindset, the ecosystem can get in your way -- or at the very least, it's not making your life easier.

For many things, this is fine. If I'm not twitter, I'm trading increased scalability for readability almost every time.

For projects that just need occasional async, I would prefer the grails 2.3 model -- http://grails.org/doc/2.3.0.M1/guide/async.html -- which will get you 95% of the way there in a more readable way. ___

However, I am a bit more charitable toward node. I think this may be a case where there is enough momentum that, as people start hitting the harder problems, engineering solutions will sprout up, and the platform will mature with better patterns turning up (including generators and promises.)

This is slightly off topic, but if we're talking about language capabilities for async:

Something I only figured out fairly recently but that shocked me is that Haskell, with its lazy evaluation, you can essentially get asynchronous programs for free, and still write in a synchronous style.

While by default the IO monad is strict (basically makes IO stuff synchronous), there are some non-strict actions that are really easy to use.

Imagine the following program:

Open two ports, and print the first couple of bytes recieved from each port.

In node (at least from the callback-based stuff), at one point you're going to have an inevitable :

  while(!done){} //waiting
in Haskell, this program looks roughly like:

  main = do
   socket    <- someSocketInitCommand
   socket'   <- someSocketInitCommand
   response  <- hGetNonBlocking 1024 socket
   response' <- hGetNonBlocking 1024 socket'
   print ("1st socket : "++ response ++ "\n second socket:"++response')
Lazy IO in Haskell is what I call blocking on data-dependencies: because of how lazy evaluation works, Haskell is able to keep on going until the very moment you need the result from some async call.

It's even crazier that Haskell has the holy grail of async programming : the function that transforms a synchronous function to an asynchronous one.

Instead of having

  main = do
     x <- a
you simply do

  main = do
     x <- unsafeInterleaveIO a
a becomes asynchronous , and nothing else in your code has to change.

(from what I understand unsafeInterleaveIO is called like that because it makes the order of your IO actions a bit uncertain, which is a problem for print statements, but when you're doing async programming this is already the case!)

Laziness makes Haskell crazy neat, and I would really love for lazy features to enter other languages. There are some issues (error handling mainly) but it gives you the best of both worlds, I find.

( I am by no means a Haskell expert, so all this might be wrong, but in my experience things work this way-ish)

That's not all. This code:

    foo = do
        result <- do_first_thing
        do_second_thing result
Kinda sorta roughly desugars into something like this:

    function foo(cb) { do_first_thing(function(result) { do_second_thing(result, cb); }); }
Synchronous and asynchronous Haskell APIs can have the exact same interface.
Look at Akka, it brings a very rich concurrency toolkit to the JVM, building on the already-excellent primitives provided by the standard library.

Futures and actors are quite elegant and simplify reasoning about concurrency.

I'm always wondering why gevent never gets the same attention other concurrency frameworks do. From my point of view it looks like a very sweet library with useful tools and should work just fine in combination with gunicorn or uwsgi. I never had a chance to test it with some real work load though.
Problem is the lack of third party libraries that does IO the way gevent works, if your lib does blocking IO, there is no point using gevent.

NodeJS does async IO by default,so all nodejs libs do async IO.

My point is , it's not so much about wether ruby or python can have the same capabilities as nodejs they can,it's about wether async libs have an ecosystem to support them or not.

If you lib uses standard library primitives (sockets, pipes, subprocesses, etc) then gevent.monkey makes it cooperate.
"Problem is the lack of third party libraries that does IO the way gevent works, if your lib does blocking IO, there is no point using gevent."

Here we probably see some of the problem. Gevent works in a way that most people don't expect, which is to hack the IO layer itself. You don't need a library to "support" gevent for it to still work within gevent. If the library's "synchronousness" is that it opens sockets and uses them, that Just Works in gevent; every time the library does a "blocking" operation in gevent, gevent replaces it with an entry in some sort of polling loop, and moves to the next eventlet that can do work. I used it to write a highly concurrent program that made a ton of simultaneous XML-RPC calls, and I used gevent + the default "blocking" XML-RPC library from Python's core library. It makes the ecosystem support async, at least for network, timers (sleep), and a few other things.

Gevent has other issues; I don't think it can do the same for disk IO. But especially if you've got a network heavy program, you can just drop gevent in and get perfectly cromulent async.

I think a lot of people don't quite understand this. The Node community's persistent and vocal false belief that "async == visibly event-based structure code" probably isn't helping. But it is also true that gevent is a legitimately weird hack on a language. Cool, but very unusual.

One can monkey-patch __builtins__, too, so `open("foo", "r").read()` will happily yield control to event loop. It's just that gevent doesn't do this.

Sounds like a great project to hack in spare time, though.

It's an "informercial" from a company which core business is providing nodejs commercial tools and consulting, what did you expect them to say about NodeJS ?
I have gotten to the point where I just can't take seriously anyone who equates "the async style" to "Node's event based system" as if Go, Erlang, Scala, Clojure, etc. don't exist. No, you do not have to choose between speed and sacrifice a sane coding style, and anyone still pushing that Node propaganda is just not worth listening to.

Node is consistently beaten by multiple Go and Java frameworks across all benchmarks [1], consistently beaten by Scalatra, somewhat inconsistently beaten by the Haskell wai implementation (missing some benchmarks, I suspect wai would continue winning though if they were implemented; also I think those benchmarks are on an older Haskell IO manager). Not only are you choosing a dangerous coding style, you're not even winning the performance you think you are. Node is not faster. And certainly every library for Go, Haskell and Erlang, and probably everything for Scala and Clojure (not 100% sure of their runtime models) is already "async ready", and Java itself probably isn't exactly running short of libraries at this point.

[1]: http://www.techempower.com/benchmarks/#section=data-r8&hw=i7...

I agree, they should at least compare to Go.

However, it is fair to say that when using Java, you have to choose carefully since many API's block on I/O, including those that Java programmers use by default and are most likely to be familiar with.

The biggest impediment to async programming in Java-land is the lack of an async JDBC driver.
It's really not that hard to make thing run async / paralell in java: You just create a ExecutorService and submit your runnables / callables. The java.util.concurrent-package makes this easy, and google guava has some useful extensions as well (e.g. ListenableFuture). This approach does of course spawn new threads, but threads are lightweight and using a ExecutorService allows for pooling of the threads (ThreadPoolExecutor). I do this all the time, when I find parts of the code that's worth optimizing - e.g. fetching multiple objects from a distant db-server (like aws).
What about generators and stuff like Koa[1]? Do you dismiss them too? You don't have to use events all the time, and it's trivial to wrap most Node IO as promises, thunks or whatever it is that you like, and then use generators as syntax sugar to work with them.

[1]: http://koajs.com

Still incredible hacks compared to a language that just does it right, you get composition problems with having so many techniques floating around that require adapters to work with each other, and you're still writing a ton of code that is simply paperwork, that the compiler could be doing instead. And it's nasty, error-prone paperwork too.

Remember, Node did not originate a single one of those techniques, despite what it sometimes sounds like. They're rediscovering them from the other communities that tried them, and subsequently discovered that the techniques did not solve their concurrency problems. Watching the Node community has been like watching the greater concurrency community's last 40 years compressed into 4 years; we are right on the verge of the inevitable recognition that these techniques won't save them either (I'm seeing the first traces of this in various blog posts), followed by an eventually dimming of Node's vitality as it slowly becomes clear that Javascript just can't do what Node is asking it to do, at scale. (Can not emphasize the "at scale" enough. Anything works on small cases. Node is good enough to work at medium cases, though the effort starts getting greater distressingly fast, which is only noticed by those who have worked in a saner environment. But it's just not going to work at scale any more than any of the other half-a-dozen virtually identical languages with virtually identical capabilities and virtually identical programmers.)

Why is it a dangerous coding style? The new Node will have support for yield / generators that result in beautiful async code.
Of course, beauty is in the eye of the beholder, but I would say yield statements are not beautiful, they're just less ugly. Having lots of yield statements sprinkled throughout my code is (again, in my eyes) ugly. Less ugly than callback pyramids, but still ugly.
Try Go; get back to me on the beauty.

"Beautiful async code" is where the async is essentially invisible, because everything just is async.

It is indeed mind boggling when people list async (read: callback hell) as a feature. Complex systems rapidly get unmanageable, so people build nasty hacks to try to paper over the async core (it is still async single threaded at its core, run a dumb busy loop and watch your app stop responding).

Blocking is a feature. Blocking lets you reason easily, and as Go, Erlang, etc... have proven can be done at breathtaking speed and use all your cores... rather than wrapping your world view around async, use a system that allows you to keep your logic blocking and uses microprocesses to distribute work across a pool of threads. It is freeing to be able to just kick up 300k microprocesses if you need them.

Additionally, the node ecosystem tends to be quantity over quality... many of the available modules are simply more trouble than they are worth... while NPM makes getting them easy, it doesn't make deciding if something is worth using any easier.

Systems such as Go's goroutines, or clojure's core.async, or objective-c's GCD all solve the same concurrency problem while still allowing you to saturate all of your cores from a single process.

This allows you to get around some nasty architectural problems you can hit with node, where you must either find a way to manually schedule all of your computation into tiny chunks to avoid latency issues, or face potentially severe costs serializing your data to communicate it between processes. No trolling here, it's really a thing that happens!

People do solve these problems in node, it's just that the "ease" suddenly turns against you, as you must now solve tricky systems problems - such as manually scheduling all of your computation properly - or face potentially unacceptable performance degradation. In these cases the limitations of the platform become your overriding architectural driver - better drivers like logical separation start to take a back seat. It's not pretty - and not necessary in other environments.

Given that you won't encounter these types of problems until later - once you've already built up a large codebase and switching platforms is difficult - I think it's better to start in an environment where you know you have these tools available to you when you need them. Even though I really enjoy programming in node (and I've done a lot of it!), I'm wary of starting anything new there unless I have a good reason. There are a lot of great modules written in node, I just try to keep those components isolated and not let them grow too large.

> At high levels of concurrency (thousands of connections) your server needs to go to asynchronous non-blocking.

It does. But it doesn't have to expose that as callback chains or promises to the whole over-arching infrastructure that sits on top. Concurrency units should be isolated from each other and internally execute whatever their logic is without having to worry about being polluted with callbacks. Then there could be multiple of such concurrency units executing in parallel but that is a the job of a decent VM/runtime/library to handle.

> And at these levels of concurrency, you can’t go creating threads for every connection.

Even something as simple as python gevent can create tens of thousands of green threads without a problem without exposing callback chains for everyone to see.

Erlang VM and something like https://github.com/puniverse/quasar can run with millions of concurrency units so do goroutines and Rust's concurrency units (sorry forgot the name).

> So the whole codepath needs to be non-blocking and async, not just the IO layer.

Quite the opposite. If your whole codepath riddled with callback chains and your project is large now you have a huge headache to deal with.

> This is where Node excels.

If it forces one to use promises/deferreds/futures or nested callbacks, I say it fails.

"But there’s one thing we can all agree on: At high levels of concurrency (thousands of connections) your server needs to go to asynchronous non-blocking."

No, we can't all agree on that. Asynchronous non-blocking might be better in limited scenarios where threads are expensive (memory or cpu or other constraints).

"While Java or Node or something else may win a benchmark, no server has the non-blocking ecosystem of Node.js today. Over 50k modules all written in the async style, ready to use."

Sad to see so much work go into a faulty design. Take a look at this presentation http://www.slideshare.net/e456/tyma-paulmultithreaded1.

What makes bullshit articles more common than valuable articles? It's all about being a self-educated asshat with a lot of ego and second-order ignorance.
I wish the author had considered middleware components written with Netty -- they are async and highly concurent as well.

Moreover, Servlet 3.1 Specification , which is a part of Java EE7, includes JSR-340 Non-blocking I/O. In a typical application , ServletOutputStream and InputStream do read/write in a while loop while holding on to the request thread. This issue is potentially resolved in Servet 3.1 by adding event listeners – ReadListener and WriteListener interfaces. These are then registered using ServletInputStream.setReadListener and ServletOutputStream.setWriteListener. The listeners have callback methods that are invoked when the content is available to be read or can be written without blocking.

The new versions of Glassfish and Tomcat servers already support Servlet 3.1.

So Java already supports async style web applications. The programmers have to brush up their skills.

Java blocking I/O is faster than non-blocking, at least on Linux. This is kernel level, not language level.

http://www.slideshare.net/e456/tyma-paulmultithreaded1

You have to be very careful what you mean by "faster" in this case. For the use case documented in those tests I assume he was measuring sustained throughput (it isn't documented well what he means by 25% slower). He was also testing a server that had lots of connections and not many messages per connection. In that case modern Linux can scale threads very well.

I've done tests in other cases where NIO had nearly the sustained throughput of the blocking libraries, but had much less jitter. That is the latency through the server was much more consistent with NIO libraries than with the blocking ones. This was in a protocol with few connections but lots of messages per connection.

So blanket statements about the blocking IO vs the NIO libraries being faster require more nuance than that.

> Over 50k modules all written in the async style, ready to use

Is this even true? There are "57 210" modules in NPM at the moment but many of them are explicitly synchronous

Node is certainly not faster in many cases AND in many cases nonblocking IO is NOT what you want. Sometimes sequential makes way more sense.

For example, I wrote a node script that would run a bunch of compilations of files for custom less and javascript minifacation and other stuff on a large codebase. Node opened so many file connections it would crush the machine and not finish.

A simple bash script ran in about a second.

My point is you should definitely NOT use Node because you think it's faster than Java in every case. In fact, evented everything is a pretty terrible trade off in terms of code quality for performance.

There are so many better/easier/cheaper ways to get a high performance, reliable system without using Node.

(comment deleted)
One discussion that tends to not be had in these types of benchmarks is about memory, resource utilization, and the fact that blocking is a feature.

In a typical multi threaded web application scenario, there's usually two main resources floating around: http thread pools, and database connection pools.

Both are typically designed to not scale up too quickly (e.g. wait a bit before adding a new resource) and block when they hit a configured maximum. This is because it is pretty easy for a single web server these days to become a denial-of-service attack on a database, and it's also pretty easy for a single client (especially as the typical home's Internet bandwidth increases) to become a denial-of-service attack on a web server. Sensible defaults should therefore take into account that a web server should be a good actor in an ecosystem, not that a web server should be a requests-per-second speed demon. When I read benchmarks, I tend to believe that they are essentially testing these defaults, because there is rarely discussion of them. A conservatively tuned database connection pool will block earlier in the load test, but I will respect the conservative defaults of the framework in question.

Memory is also crucially important in the sync-vs-async discussion. Once you decouple request state management from a constrained-sized thread pool, you have to predict how much memory each state will consume. Unless you are doing very little work on each request (and the work will go up as you add features), you will consume your web server's memory with request state far before you exhaust its other resources. In a threaded model, the thread overhead itself takes a lot of memory, so request overhead per thread in a threaded model is higher than an async model. But when you're talking about a web application with increasing numbers of features, this becomes less and less the majority of the request.

Here's a sketch of an example. In the typical thread-pool based model, X requests can happen simultaneously based on the configured maximum of handler threads--if more requests come in than can happen at the same time, they go into a queue. This is nice because unless the web application is very simple, it's far easier to predict the memory overhead of http requests in a queue than active simultaneous requests in the application layer, especially because most web servers put maximums on the size of individual http headers. In other words, the memory cost of each http request in the queue is constant, while the memory-per-request-state in the application layer will grow with the number of features that layer on the application.

Of course none of the above has much to do with asynchronicity vs thread-bounded-ness. You can have a web server with a request queue and then a set of asynchronous handlers that feed off the queue. I do have a weak argument for threads in this scenario. In the constant tug-of-war between server resources and request throughput, monitoring becomes very important. In a thread-based-model, it is easy to use operating-system tools to introspect the threads because the operating system knows what they are. In the asynchronous model the process is a heap of undifferentiated ram. In that scenario you need good tooling to predict how well tuned your request state is relative to resources. In the JVM it's pretty easy to do a heap dump and see how much memory each request is taking, I'm not sure if there's an equally convenient scenario in the Javascript runtime(s) Node.js can utilize, but I'm sure there's a way. What I do know, however, is that complexity increases as you add actors and/or callbacks, because request state is now broken into a chain of independent memory consuming entities, as opposed to a single predictable thread stack and references.

In the midst of all the above I tend to go for flexibility, because the needs are situational. Async when you need it, sync when you need it. With sync being the more predi...

Node.js has linear speedup over multiple cores for web servers, no other language can claim that.
Excuse me, but you've mistyped the word "any" in "any other language" part.

Last time I checked, event loops and async IO wasn't anything Node had monopoly on. In fact, those are available on every non-toy general purpose platform I remember off my head.