2
\$\begingroup\$

There is an article where the author tries to compare performance of different web stacks. The result looks pretty controversial. I try to prove that in real use case the difference between scores of different stacks will be not so significant(under "real" I mean something which relies on database) .

For this purpose I take two stacks: one from the top side(node+express) and the looser(python+flask). And now I'm trying to implement a little bit more realistic use case for both platforms.

This is the code for the flask application:

#app.py
from flask import render_template
from flask import Flask
import sqlite3

conn = sqlite3.connect('data.db')
app = Flask(__name__)
c = conn.cursor()
if c.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='data'").fetchone() is None:
    c.execute("CREATE TABLE data (value TEXT)")
    conn.commit()
conn.close()

@app.route('/<int:number>')
def index(number=1):
    conn = sqlite3.connect('data.db')
    c = conn.cursor()
    c.executemany("INSERT INTO data VALUES (?)",   [(fib(number),)] * 10);
    list = c.execute("select * from data limit 100").fetchall()
    conn.commit()
    conn.close()
    return render_template('template.html', list=list)

def fib(n):
    if n == 0: return 0
    elif n == 1: return 1
    else:
        return fib(n - 1) + fib(n - 2)

if __name__ == '__main__':
    app.run(debug=False)

#template.html
<ul>
{% for l in list %}
    <li>{{ l[0] }}</li>
{% endfor %}
</ul>

And the code for node application:

// app.js
var express = require("express");
var jade = require('jade');
var db = new (require('sqlite3').verbose()).Database('data.db');
var app = express();

var fib = function (n) {
  if (n === 0) {
    return 0;
  } else if (n == 1) {
    return 1;
  } else {
    return fib(n - 1) + fib(n - 2)
  }
};

var getApp = function () {
    app.get("/:number", function (req, res) {
      var number = req.param("number"); 
      query = db.prepare("INSERT INTO data VALUES (?)")
      for(var i=0; i<10; i++) {
        query.run((fib(number)))
      };
      db.all("select * from data limit 100", function(err, rows){
        var rendered = jade.renderFile('template.jade', {list: rows})
        res.send(rendered); 
      });
    });
    app.listen(3000);
}

db.get(
  "SELECT name FROM sqlite_master WHERE type='table' AND name='data'",
  function (err, row) {
    if(err !== null) {
      throw new Error();
    }
    if(row === undefined) {
      db.run('create table data (value text)', getApp)
    } else {
      getApp()
    }
  }
);

# template.jade
ul
    each l in list
        li=l.value

Questions

  1. Some advice about node code. How can I make it more idiomatic and beautiful?
  2. There is some strange behavior in the node app. Benchmark results proposed below should describe it. What I'm doing wrong?

I would be glad to achieve any piece of advice about improving these code samples.

Running 30s test @ http://localhost:3000/10
2 threads and 64 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    26.19s     4.89s   28.93s    77.14%
    Req/Sec     0.87      1.46     4.00     86.67%
  64 requests in 30.01s, 81.25KB read
  Socket errors: connect 0, read 0, write 0, timeout 896
\$\endgroup\$
2
\$\begingroup\$

Since the Fibonacci algorithm is so nice and clean there is one little nitpicky thing to add. You don't need to directly return 0 and 1 in the base cases, you can just return n. So the function can be rewritten (in Javascript, my experience with Python is extremely subpar) as:

var fib = function(n) {
    if(n === 0 || n === 1) {
        return n;
    }

    return fib(n - 1) + fib(n - 2);
}

The algorithm is beautiful but it also does a lot of extraneous work when run in a loop, that can be removed with the technique of memoization (again, to keep these tests fair, I think (?) this is possible in Python as well but someone else could be of more use in helping with the code). In this specific case, the technique is incredibly easy to employ with a simple Javascript object as a cache

var fib = (function() {
    var cache = {};

    function fibonacci(n) {
        if(n === 0 || n === 1) {
             return n;
        }

        return fibonacci(n - 1) + fibonacci(n - 2);
    }

    return function(n) {
       if(n in cache) {
           return cache[n];
       }

       return fibonacci(n);           
    }
}());
\$\endgroup\$
  • \$\begingroup\$ Thanks, for the answer! In reality I use fibonacci algorithm just as simple computation and there is no reason to optimize this \$\endgroup\$ – kharandziuk Sep 7 '14 at 7:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.