Express vs Flask vs Go vs Sparkjava
Fibonacci(10) Calculation per Request: Sparkjava blasts away the others performance wise.
- 4 min read
UPADTE: I added Sparkjava to the tests and even though it consumes more memory (about 140MB) it handles 48631 requests per second while Golang handles 37756 requests per second
Today I decided to do a little benchmark of some of my favorite web stacks. So I created a web service that calculates the corresponding fibonacci number to a request parameter. Go’s performance is way higher than node’s and python’s.
The Code
A request to for example http://localhost:3000/10 calculates fib(10) and returns the result (55 in this case) as plain text. I think it’s better to have a little computation per each request because it is more realistic than just serving “Hello World”.
Node + ExpressJS
I chose ExpressJS as it is node’s de facto web framework.
var express = require("express");
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)
}
};
app.get("/:number", function (req, res) {
var number = req.param("number");
var result = fib(number);
res.send("Node + Express<hr> fib("+number+"): "+result);
});
app.listen(3000);
Python + Flask
For Python I chose Flask because it is very popular among Pythonistas (Geeky word for Python Programmers) and comparably small in size.
from flask import Flask
app = Flask(__name__)
@app.route('/<int:number>')
def index(number=1):
return "Python + Flask<hr>fib("+ str(number) + "): "+ str(fib(number))
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)
Golang + Gorilla Pat
As golang comes already with a nice net/http package one doesn’t really need a framework to handle requests. What golang lacks in my opinion is a routing system that supports url variables for it’s request handlers. Here I chose Gorilla Pat because it is small and for this test I don’t need additional stuff like subrouting, subdomains, etc.
UPDATE: I now used the original Pat Router and it’s way faster now.
package main
import (
"fmt"
"net/http"
"strconv"
"github.com/gorilla/pat"
)
// fib returns a function that returns
// successive Fibonacci numbers.
func fib(n int) int {
if n == 0 {
return 0
}
if n == 1 {
return 1
}
return fib(n-1) + fib(n-2)
}
func IndexHandler(w http.ResponseWriter, r *http.Request) {
string_number := r.URL.Query().Get(":number")
number, _ := strconv.Atoi(string_number)
fmt.Fprintln(w, fib(number))
}
func main() {
r := pat.New()
r.Get("/{number:[0-9]+}", IndexHandler)
http.Handle("/", r)
http.ListenAndServe(":4000", nil)
}
Sparkjava
This framework is a pretty lean package that makes use of Java8 Lambda support. It comes bundled with Jetty 9 even though it can also be deployed on other servers.
import static spark.Spark.get;
public class HelloWorld {
public static void main(String[] args) {
get(“/:number”, (req, res) -> {
int number = Integer.parseInt(req.params(“:number”));
return “Sparkjava: fib(“ + number +”) = “ + fib(number);
});
}
public static int fib(int n) {
if (n == 0) {
return 0;
} else if (n == 1) {
return 1;
} else {
return fib(n — 1) + fib(n — 2);
}
}
}
The Result
I tested with wrk with the following settings:
wrk -c 64 -d 30s http://localhost:PORT/10
1. Sparkjava:
48631.24 Requests/sec => 1458768 requests in 30s
Average Latency 1.29ms
2a. Golang + bmizerany Pat:
42222 Requests/sec => 1266661 requests in 30s
Average Latency 1.52ms
2b. Golang + Gorilla Pat (using Gorillas Muxer)
37756 Requests/sec => 1132689 requests in 30s
Average Latency 1.71ms
3. Node + Express:
8962 Requests/sec => 268866 requests in 30s
Average Latency 7.14ms
4. Python + Flask:
546 Requests/sec => 16393 requests in 30s
Average Latency 55.54ms
As one can see Spark’s & Go’s results are in another league than the other two. At least this is the case on my System.
Setup:
Hardware: Retina Macbook Pro i7@2.7GHz and 16GB RAM
Software: OSX 10.9.3
Java 8 + Sparkjava 2.0.0
Golang 1.3
Python 2.7.7 + Flask 0.10.1
Node v0.10.29 + Express 4.4.4
A note about memory usage:
All of the three technologies didn’t consume much memory during the tests. Node was about 17MB, Python 14MB and Go about 5MB of RAM.
UPDATE: Sparkjava consumed about 140MB of RAM even though this is pretty normal for the JVM.
Conclusion (Updated)
If you need raw computing performance for the web Golang might be for you. Node + Express is also not slow. Python with Flask is slow compared to the other two.
I didn’t include a Java test in this benchmark but you can expect a much higher memory usage. Also I might add a benchmark result using PyPy.
UPDATE:
Sparkjava is the fastest in this test and if you are into the JVM this seems like one of the fastest options currently available.
If you read this far you should follow me on twitter: @tschundeee ☺