9 ms·
Node.js Versus LUA "Hello World" HTTP Server Showdown
- amix 16y agoWhat versions of node and Lua are used in the benchmark? Where can SXE be found (Google can't seem to find it)...?
- rbranson 16y agoLet's remember that Node.js is more about predictability, scalability, and (most of all) simplicity of development, than performance. Lua(JIT) is indeed impressive, but having to learn another programming language is a huge downside.
- nwmcsween 16y agoYou never really learn a new language in the case of syntax that's all peanuts. Javascript and Lua are both prototype based languages and such trivial differences exist that can be ironed out over a week of productive use.
- pygy_ 16y agoIn my case, it was a couple of days. I read the free online version of the Programming in Lua[1] book and was basically set. Lua feels like a simpler, cleaner Javascript. -- You have lexical scope, anonymous and first class functions, and dynamic typing. The parser is as simple as possible (LL(1), ie top down, without backtracking), and doesn't do any magic like declaration hoisting or semi-column insertion. The only falsy objects are `false` and `nil`. `==` doesn't do any type conversion. The addition `+` and concatenation `..` operators are different. Some infix operators do automatic type conversion ( +, -, *, /, %, ..) between strings and numbers, but that's about it for weak typing. There's no octal to decimal conversion for strings with prepended zeros. There's only one way to define objects. The `self` parameter is explicit for methods, but there's syntactic sugar to pass it automatically. Scoping is similar: variables are global by default, which allows precise scoping for closures. -- == Where the languages diverge: You can do some magic with metatables and environments, but once again, the mental model is extremely simple. The other major differences are coroutines (cooperative threads) and a "generic" `for` loop that allows to build custom idiomatic iterators. At last, the array indexing starts at 1. This may sound like heresy to devout Dijkstra followers, but it's really not a big deal in practice. -- [1]: http://www.lua.org/pil/ http://www.lua.org/pil/ by Roberto Ierusalimschy, one of the author of the language.
- mhansen 16y agoWow - thanks for this summary. I hadn't heard a rundown like this before. That sounds great - I might give Lua a go!
- notthinking 16y agoI think the most compelling thing about Lua (to someone with no Lua experience), is that its appears (from examples, and what people have said) that its good for embedding inside another program (size wise and good FFI). In a video I saw, by one of the designers of the languages stated that this was the original purpose (engineers using this instead of C, with the low level details done by programming team in C).
- pygy_ 16y agoIndeed, C(++) interop is easy. The API is also described in the PiL Book linked above. Furthermore, the VM binary weights 200k. It is extremely portable (it uses the common subset of C89 and C++), and its code is a pleasure to hack.
- notthinking 16y agoJust had a quick skim over some of that chapter, and it is very compelling, especially when I see how well its worked for AwesomeWM (my desktop environment of choice) and how many commercial games are using it for user scripting [1]. [1] http://en.wikipedia.org/wiki/Category:Lua-scripted_video_games http://en.wikipedia.org/wiki/Category:Lua-scripted_video_gam...
- moonpolysoft 16y agoScalability, eh? What about that whole "scale beyond a single CPU" thing. I hear it's quite the rage.
- a2800276 16y agoWhat about that whole "fork" thing. I hear it's quite the rage
- moonpolysoft 16y agoLast time I checked Node.js was not able to invoke fork.
- simonw 16y agoIt can spawn child processes: http://nodejs.org/api.html#child-processes-89 http://nodejs.org/api.html#child-processes-89 http://www.sitepen.com/blog/2010/07/14/multi-node-concurrent-nodejs-http-server/ http://www.sitepen.com/blog/2010/07/14/multi-node-concurrent...
- KirinDave 16y agoYour OS's copy-on-write page policy loves when you fork things using mark-and-sweep garbage collection. It is full of rage.
- pjscott 16y agoIf node can scale beyond a single machine, then it can scale beyond a single CPU on a machine. I know I'm oversimplifying, but you're oversimplifying more.
- moonpolysoft 16y agoSo last time I looked at it, Node.js did not have any language level or even library primitives for message passing. At least nothing beyond making you open a socket and work out your own protocol for IPC. I'll grant you that is the standard scalability story for most languages running on multiple hosts. However it seems deficient if one's goal is to make use of most of the cores on modern server hardware.
- KevinMS 16y agobut having to learn another programming language is a huge downside Not if you can also use it to write World Of Warcraft addons :)
- Tichy 16y agoGot a link? I wasn't aware that it is possible for common people to write WoW addons?
- scalyweb 16y agoProbably the best starting point: http://us.blizzard.com/support/article.xml?locale=en_US&articleId=21466 http://us.blizzard.com/support/article.xml?locale=en_US&...
- cheald 16y agoIndeed. I learned it doing that, and have come to appreciate what a marvelous little language it is. Always a pleasure to work with.
- KirinDave 16y agoAttitudes like yours make me sad, on many levels. It also makes me mad, because by every metric save the what-you-already-know, Lua is at least comparable, if not outright superior.
- ay 16y agoStrings operations is a tricky part though. It's easy to slow the code down with "obvious" coding - which is a bad thing in a language. Some other operations like metatable lookup might not be always the fastest. But overall the convenience of having a 700K source tarball that compiles on any ANSI C into a modern language blows all these concerns away for my use. And the performance-critical parts can be easily pushed down to C. If they are not premature optimizations to begin with.
- silentbicycle 16y agoHow are string ops tricky in Lua? Patterns and table.concat can get a lot done, and when you need more power, there's LPEG (which is also quite speedy).
- ay 16y ago"Patterns and table.concat can get a lot done" - sure. but it is may feel somewhat backasswards :-) $ time lua -e 's="";for i=1,100000 do s=s.."-";end' real 0m1.292s user 0m1.029s sys 0m0.108s $ time lua -e 't={};for i=1,100000 do table.insert(t,"-");end; s=table.concat(t,"")' real 0m0.284s user 0m0.062s sys 0m0.077s times are somewhat bogus since it is cygwin under win7, but they give the impression of what I am talking about. I do not argue it is a feature very coherent with the design of the language, and the immutable strings have other good properties. But if you do intensive string ops you need to watch out not to fall into the trap of treating the strings as mutable objects. Don't get me wrong - I like Lua a lot and use it almost on a daily basis. Just that I think the posts like this may attract some new folks to try Lua out - and they deserve to know the obvious ways they can shoot themselves in the foot in order to avoid some disappointment.
- mmaunder 16y agoThis comment was ranked 0 when I found it. It's exactly right. Startups are risky enough without having to hire a team of Lua developers. An async server that supports a mainstream language is awesome. Lua? No.
- ay 16y agoIn this case, you would be looking at PHP and Java, not node.js. Last time I checked node.js and libraries for it (about a couple of months ago), I could not run the library I wanted on the latest version of the node.js because the API has completely changed. Platform software that completely changes itself over a course of a couple of months ? Thanks but no thanks. Disclaimer: It's been couple of months. Maybe the things have changed since then, will be grateful for an educational reply from someone who has used node.js, about its maintainability, especially for the use with third party libs.
- felixge 16y agoNode's API was frozen with the 0.2.0 release (for most parts). Things were indeed very rocky before, but most libraries have been updated now and are unlikely to break again soon.
- rbranson 16y agoIt looks like the zealots got to you. I agree partially with what you're saying. Node.js is still a somewhat immature platform, but people are generally building small, single-purpose servers with it, not replacing their entire infrastructure. I don't think anyone is advocating that.
- mhd 16y agoA lot of that is true if you compare it against Erlang, which has a much different approach to concurrency – and has a steeper learning curve for a Python/Ruby+JavaScript web developer. Learning Lua on the other hand? If that's not utterly trivial, I'd be worried. The biggest downside Lua always had was that it's deeply rooted in the embedded category, where it's hard to come out from. Tcl is one the market for ages and still doesn't have a proper culture of libraries. At least Lua has its "rocks", maybe that will make it a worthwhile candidate for the non-embedded sector, too. It's a much nicer language than most of its rivals.
- silentbicycle 16y agoLua developed a "culture of libraries" recently, and is catching up. Another part of the problem was that it didn't really have a proper module system until a couple years ago (partially due to the focus on embedding). Besides LuaRocks, there's a collection on the Lua wiki (http://lua-users.org/wiki/LibrariesAndBindings http://lua-users.org/wiki/LibrariesAndBindings), and the mailing list (http://www.lua.org/lua-l.html http://www.lua.org/lua-l.html) is very active. And yeah - if you know Javascript, you won't have trouble learning Lua. It's like Javascript with less gotchas and better performance.
- mrb 16y agoHis fastest "node.js+net" case is not optimal. I could easily come up with an even faster implementation by using Buffers instead of strings by not calling setEncoding(), which makes it 30% faster on my machine. This should translate to about 37500 queries/sec on his machine: var net = require('net'); var server = net.createServer(function (stream) { stream.on('connect', function () {}); stream.on('data', function (data) { var l = data.length; if (l >= 4 && data[l - 4] == 0xd && data [l - 3] == 0xa && data[l - 2] == 0xd && data[l - 1] == 0xa) { stream.write('HTTP/1.0 200 OK\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\nContent-Length: 13\r\n\r\nHello World\r\n'); } }); stream.on('end', function () {stream.end();}); }); server.listen(8124, 'localhost');
- mrb 16y agoAnd this other version that doesn't check for "\r\n\r\n" is 47% faster than his "node.js+net" case. This should translate to about 42000 queries/sec on his machine: var net = require('net'); var server = net.createServer(function (stream) { stream.on('connect', function () {}); stream.on('data', function (data) { stream.write('HTTP/1.0 200 OK\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\nContent-Length: 13\r\n\r\nHello World\r\n'); }); stream.on('end', function () {stream.end();}); }); server.listen(8124, 'localhost');
- kurokikaze 16y agoWhy empty callback on 'connect'? It will go to event loop for every client, and yet do nothing of value.
- jasonwatkinspdx 16y agoI'm frustrated by Lua, because it seems such a productive, pragmatic language that is performant to boot (let alone the numbers LuaJIT is posting), but yet it never seems to gain momentum. Why has Lua adoption been so slow outside the game world?
- ay 16y agoI think those who find it a productive tool, just use it without waiting for the whole herd to head that direction - and since it's just a tool that provides a productivity edge - why advertise too much about it on blogs ;-) http://www.cisco.com/en/US/docs/security/csd/csd35/configuration/guide/CSDdaps.html#wp1057235 http://www.cisco.com/en/US/docs/security/csd/csd35/configura... (disclaimer: cisco is my employer). (disclaimer#2: I did use lua for quick prototypes that involved the low-level C code and higher level logic to glue it. So the positive feelings I got from it may be biasing me).
- kristopher 16y agoI think this mostly has to do with the 'Batteries -not- included' approach of Lua. This is mainly done to keep the language/vm compact and embeddable, yet what it leads to is many similar implementations of modules that do not play well together.
- manveru 16y agoI read a related article a while back: http://journal.dedasys.com/2010/03/30/where-tcl-and-tk-went-wrong http://journal.dedasys.com/2010/03/30/where-tcl-and-tk-went-... It's interesting to draw parallels to Lua, they both started out as embedded scripting languages with a small core.
- davidw 16y agoGreat article:-) I think managing the addition of batteries is definitely tricky for a language like Lua. Some of its users do not want any additional baggage: they want small, fast and easy to embed. Other people may want to use it as a 'scripting language', and thus want to have a bunch of libraries and additional goodies to get stuff done with.
- malkia 16y agoLuaJIT 2.00 calls "C" functions a bit slower than reference lua or luajit 1.00. Mike Pall explained that in the newsgroup, if I'm not wrong. But the idea with LuaJIT is to use "C" much less.
- pygy_ 16y agoIIRC, code sections with foreign call cannot be traced by the compiler... Or, if they can be, the performance would be worse than not doing it (my memory is a bit foggy). A custom API for LuaJIT is in the works, to alleviate this problem. Extensions will have to be written twice though, if one wants to support both runtimes.
- silentbicycle 16y agoIt's Lua, not LUA. Not an acronym. (It means "moon" in Portuguese.) Could you correct the title? Also: Serving "Hello World" is not a very informative benchmark, especially for an async web stack. Something like making an asynchronous database request and then sending the response may be more representative. If you want to eliminate the database response time variable, then write a C program that listens for incoming connections and responds with "Hello world" or something, but either way, make it actually do some work server side.
- simonhf 16y agosilentbicycle, thanks, I updated the name as suggested. So do you have any ideas for a more interesting benchmark program? Ideally it should be something which needs to keep state as you suggest and makes use of some kind of simple business logic, and is only a few hundred lines of code at the very most. What about a simple chat server which handles people and rooms? The benchmark might handle, say, max. 10k people chatting in max. 1k rooms. What do you think? Any better ideas?
- silentbicycle 16y agoI think a server that takes a login and password, sends the pair to another core (or server) to do a bcrypt (http://www.openbsd.org/cgi-bin/man.cgi?query=bcrypt http://www.openbsd.org/cgi-bin/man.cgi?query=bcrypt) check, and then responds with a pass/fail would be a good benchmark. An async web stack benchmark server should juggle loads of concurrent connections while making internal requests to another process or server, and then sending the response (when available). That's representative of a lot of common server tasks, yet can control for the work itself. I'm suggesting bcrypt in particular because the amount of CPU time per client can be easily controlled. (In a nutshell, bcrypt is a hash function which can be made arbitrarily slow to deter password cracking.) Offhand, I'm not sure which systems have bcrypt besides OpenBSD, though. FWIW, I have a simple bcrypt wrapper for Lua (http://github.com/silentbicycle/lua-bcrypt http://github.com/silentbicycle/lua-bcrypt). There's also a Ruby bcrypt wrapper (http://github.com/codahale/bcrypt-ruby http://github.com/codahale/bcrypt-ruby) which includes a copy of the bcrypt source from OpenBSD. I feel vaguely uneasy about including that with my Lua wrapper (it really should be its own library, and more widely available!), but may eventually do so.