Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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)
@Garciat

This comment has been minimized.

Copy link

@Garciat Garciat commented Jan 28, 2011

Probably the fact that you can error-check on the callbacks and act accordingly. I sort of agree with you, though. Python code is more elegant, but JavaScript, to me, is easier to write. For some reason, JS "clicks" better in my head.

@cgbystrom

This comment has been minimized.

Copy link
Owner Author

@cgbystrom cgbystrom commented Jan 28, 2011

Well, synchronous code is definitely better. Easier to reason about. But I do see the advantages offered by node.js. Perhaps not so much from the callback structure, but for the similarity to client-side development.

@devhd

This comment has been minimized.

Copy link

@devhd devhd commented Jun 3, 2011

You can start in node.js four processes at the same time: 2x memcached.get(...) and 2x mongo.find(,,,). Ater that use a common callback (or deferred). It will be asynchronous an usually faster.

@cgbystrom

This comment has been minimized.

Copy link
Owner Author

@cgbystrom cgbystrom commented Jun 3, 2011

I'm sure node.js with V8 is a lot faster than Python. What I was arguing about was that the code gets very hard to follow with complex callback hierarchies. With coroutines, found in gevent and Go for example, structure appears blocking and thus much easier to follow.

@cgbystrom

This comment has been minimized.

Copy link
Owner Author

@cgbystrom cgbystrom commented Sep 15, 2011

I wrote a blog post earlier this month of what makes node.js popular. http://blog.cgbystrom.com/post/9518338400/six-reasons-why-node-js-is-so-popular

@devhd

This comment has been minimized.

Copy link

@devhd devhd commented Sep 15, 2011

node.js is an interesting plattform, but not so mature as Python world. Speed of the interpreter is not a first criterion, but the person who writes a code. I check node.js for some tasks, because I use JavaScript and Python in my projects.

@lvaz

This comment has been minimized.

Copy link

@lvaz lvaz commented May 4, 2012

Your Javascript it's just bad. You can write elegant code in Javascript, just check this library https://github.com/caolan/async. You can parallelize tasks elegantly with async, you don't need to chain callbacks...

@truongsinh

This comment has been minimized.

Copy link

@truongsinh truongsinh commented Feb 15, 2013

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

This comment has been minimized.

Copy link

@truongsinh truongsinh commented Feb 16, 2013

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

This comment has been minimized.

Copy link

@tobsn 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

This comment has been minimized.

Copy link

@vijayphadke vijayphadke commented Oct 7, 2013

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!)

@crimsonalucard

This comment has been minimized.

Copy link

@crimsonalucard crimsonalucard commented Jun 15, 2014

In terms of performance, nodejs wins.

@stevage

This comment has been minimized.

Copy link

@stevage 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

This comment has been minimized.

Copy link

@charliemitchell charliemitchell commented Feb 1, 2017

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.

@franky03

This comment has been minimized.

Copy link

@franky03 franky03 commented Mar 21, 2017

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

@ephetic

This comment has been minimized.

Copy link

@ephetic 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

This comment has been minimized.

Copy link

@alexei-sch alexei-sch commented Jul 27, 2017

@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

This comment has been minimized.

Copy link

@worldmind worldmind commented Jul 2, 2018

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
You can’t perform that action at this time.