Skip to content

Instantly share code, notes, and snippets.

@cgbystrom
Created December 1, 2010 20:56
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cgbystrom/724208 to your computer and use it in GitHub Desktop.
Save cgbystrom/724208 to your computer and use it in GitHub Desktop.
node.js vs Python with Greenlets
/*
node.js vs Python with Greenlets (say gevent)
I don't get why node.js is being so hyped.
Sure, the idea of writing things in JavaScript both on the client and server-side is really nice.
And JavaScript really fit an event-driven environment with its browser heritage.
But why on earth is boomerang code so appealing to write? I don't get. Am I missing something obvious?
All examples of node.js I see are littered with callbacks yet Ryan Dahl thinks coroutines suck. It doesn't add up for me.
Would anyone mind explaining how node.js below is superior to the Python code at the bottom?
Semi-pseudo node.js code with express.js follows:
*/
var memcached = ...; // From node-memcached
var mongo = ...; // From mongoose
app.get('/', function(req, res) {
var a = null, b = null, c = null, d = null;
memcached.get('mykey1', function(err, result) {
if (err) {
sys.puts('Naive error');
return;
}
a = result;
memcached.get('mykey2', function(err, result) {
if (err) {
sys.puts('Naive error');
return;
}
b = result;
mongo.find({name: 'Joe'}).each(function(doc) {
// Errors handled by mongoose
c = doc.age;
mongo.find({name: 'Julia'}).each(function(doc) {
d = doc.lastname;
res.send('Hello World! ' + a + b + c + d);
});
});
});
});
});
########################################################################
# Compared to a Python semi-pseudo example based on Flask and gevent.
@app.route("/")
def hello():
a = memcached.get('mykey1')
b = memcached.get('mykey2')
c = mongo.find(name='Joe').first().age
d = mongo.find(name='Julia').first().lastname
return "Hello World! %s%s%s%s" % (a, b, c, d)
@truongsinh
Copy link

I do agree with Ivaz, especially that Yours. Basically, you are doing synchronous coding with javascript (call and wait for mykey1 to complete, then call and wait for mykey2 to complete, then call and wait for Joe, and then call wait for Julia). You should indeed use some flow control library like mentioned Async, or Step, so that you call mykey1, mykey2, Joe,Julia async'ly, and wait until all 4 complete and continue your code. At least, Memcached and MongoDB are called in parallel. That's the core philosophy of Node.js async I/O

@truongsinh
Copy link

requestHandler = function(req, res){
    Step(
        function(){
            memcached.get('mykey1', this.paralell());
            memcached.get('mykey2', this.paralell());
            mongo.findOnce({name: 'Joe'}, {age: 1}, this.paralell());
            mongo.findOnce({name: 'Julia'}, {lastname: 1}, this.paralell());
        },
        function(err, a, b, joe, julia){
            if (err) {
                sys.puts('Naive error');
                return;
            }
            var c, d;
            c = joe.age;
            d = julia.lastname;
            res.send(['Hello World! ', a, b, c, d].join(''));
        }
    );
};
app.get('/', requestHandler);

Do not hesitate to ask for code comment or correct me I am wrong.

@tobsn
Copy link

tobsn commented Jun 4, 2013

@truongsinh

app.get('/', function(req, res){
    Step(
        function(){
            memcached.get('mykey1', this.paralell());
            memcached.get('mykey2', this.paralell());
            mongo.findOne({name:'Joe'}, this.paralell());
            mongo.findOne({name:'Julia'}, this.paralell());
        },
        function(err, a, b, c, d){ res.send(['Hello World! ', a, b, c.age, d.lastname].join('')); }
    );
});

should work too...

@vijayphadke
Copy link

Both python gevents and nodejs use event loops, so technically same. But Python is much mature and broader platform. I agree with cgbystrom. From the js code snippets above it is evident that there are multiple ways to write the code (and functional style can get hard to read at times). That's where Python's simplicity and elegance shines (only one obvious way to do something!)

@pyrofolium
Copy link

In terms of performance, nodejs wins.

@stevage
Copy link

stevage commented Dec 9, 2016

With promises and ES2015:

app.get('/', function(req, res) {
    Promises.join(
        memcached.get('mykey1'),
        memcached.get('mykey2'),
        mongo.find({name: 'Joe'}),
        mongo.find({name: 'Julia'}),
        (a, b, joedoc, juliadoc) => res.send(`Hello World! ${a} ${b} ${joedoc.age} ${juliadoc.lastname}`));
});

@charliemitchell
Copy link

I would agree that ergonomically speaking the Python code is much more desirable than the overly verbose way you wrote the Node Js/Express example. But even that poorly written Node code would run circles around the python code in terms of performance. Especially under a load.

@stevage 's example is more in line with how it should be written. Any newer version of node would support that right out of the box.

If you wanted to compare an equivalent python attempt at this you would need to use asyncio and at that point, you can easily get into callback hell. (Although it can be written nicely as well)

It seems to me like your gripe with node is developer ergonomics. Your apparent lack of or disregard of domain knowledge makes a comparison very one sided. Furthermore, it's not always about how you feel. Sometimes you need to take performance into account as well. (Not saying python is sluggish by any means) I'm not saying that async programming is a silver bullet, but Node JS was built from the ground up to be async, and its adoption is a result of many things but IMHO the important thing here is IO.

To answer the question posed in your gist, the appeal to me is the performance of async IO, less context switching when doing full stack, robust error handling in callbacks, and it can handle a tremendous amount of requests with fairly little resources. This makes it cheaper to scale, and the end user experience prevails because of it.

@franklinrincon
Copy link

My world is divided in two, I love Node.js speed and Python simplicity.

@ephetic
Copy link

ephetic commented Apr 4, 2017

Super late to the discussion, but the original Python code is synchronous, right? If not, gevent or whatever is magic and magic is never easy to understand.

@alexei-sch
Copy link

@ephetic the original python code is not synchonous. It's using gevent (coroutine-based async library) which does monkey-patching of blocking python functions and replaces them with async counterparts. As a result code looks like synchronous but is run in a same way as Node.js does. And for me looks much more elegant than JS one (even in the last sample by @stevage).

@worldmind
Copy link

May wil be interesting for someone who want make python async more fast - https://github.com/MagicStack/uvloop

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment