Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
The Holy War

Go v. Node

HOLY WAR COMMENCE

It is a call to arms: which shall we write webapps in? Shall we follow the Crockfordian camp or the Pikemen? What better test of the character of men could there be apart from trifling diatribe rife with numbers absolutely devoid of context? Through the undefiled and unambiguous answers provided us by raw numerical analysis, there can be only one champion, one path of righteousness, one road to enlightenment, The One True Language. Let the grand shootout begin!

The Source

The Go Server

package main

import "net/http"

func main() {
        http.HandleFunc("/", hello)
        http.ListenAndServe(":8300", nil)
}

func hello(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("hello world"))
}

SLOC: 7

The Node.JS Server

var sleep = require('sleep');
var http = require('http');
var server = http.createServer();

var main = function(req, res) {
        sleep.usleep(25000)
        res.write("hello world");
        res.end();
}

server.on('request', main);
server.listen(8200);

SLOC: 9

Comments

Essentially the same size program to accomplish the same task.

Curl Response

The headers returned by each were grabbed with curl:

Go

$ curl -v localhost:8300
* About to connect() to localhost port 8300 (#0)
*   Trying ::1...
* connected
* Connected to localhost (::1) port 8300 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:8300
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Mon, 03 Dec 2012 16:56:17 GMT
< Transfer-Encoding: chunked
< Content-Type: text/plain; charset=utf-8
< 
* Connection #0 to host localhost left intact
hello world* Closing connection #0

Node.JS

$ curl -v localhost:8200
* About to connect() to localhost port 8200 (#0)
*   Trying ::1...
* Connection refused
*   Trying 127.0.0.1...
* connected
* Connected to localhost (127.0.0.1) port 8200 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:8200
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Mon, 03 Dec 2012 16:57:25 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
< 
* Connection #0 to host localhost left intact
hello world* Closing connection #0

Comments

Both returned the same number of headers; the node version specified keep-alives while the Go version specified the content type.

The Numbers

The numbers, as they say, do not lie.

Go

$ wrk -t32 -c32 -r10k http://localhost:8300/ 
Making 10000 requests to http://localhost:8300/
  32 threads and 32 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.61ms  411.46us   3.48ms   89.22%
    Req/Sec     0.00      0.00     0.00    100.00%
  9984 requests in 504.40ms, 1.39MB read
Requests/sec:  19793.78
Transfer/sec:      2.76MB

Node.JS

$ wrk -t32 -c32 -r10k http://localhost:8200/
Making 10000 requests to http://localhost:8200/
  32 threads and 32 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   833.59ms   73.05ms 863.37ms   99.00%
    Req/Sec     0.00      0.00     0.00    100.00%
  9984 requests in 4.35m, 1.23MB read
Requests/sec:     38.26
Transfer/sec:      4.82KB

Conclusions

The Go version completes over 500x the number of requests per second as the Node version, and transfers nearly 600x compared to the Node version.

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