LinkedIn Sourceforge Twitter

Vincent's Blog

Pleasure in the job puts perfection in the work (Aristote)

Fapws versus GO

Posted on 2019-02-10 21:17:00 from Vincent in OpenBSD fapws

I'm still looking for a replacement to the good old fapws web server. So, in this blog, I will put fapws in front of web server written in Go

The context of the comparison

As already post on this blog, I'm comparing Fapws to other web server who could be simple to use and have a small memory foot print.

This time, I'm comparing Fapws with a Web server written in Go.

Since the context of Go, I would expect much quicker results than Fapws. But, for the memory foot print, I'm interested to see which tool is the smallest.

The test methodology

I'm doing all test on the same machine. A Dell 5450 running OpenBSD 6.4.

The test will consist of ApacheBenchmark execution with different concurrent requests.

The Go program will be executed with the command: go run hello.go

For Fapws, we will do: python2.7

The Fapws code

I'm using the script present in the sample folder of Fapws3.

Since the amazing results, I've also compared both solutions when presenting static files.

#!/usr/bin/env python

import fapws._evwsgi as evwsgi
import fapws
import fapws.base
import fapws.contrib
import fapws.contrib.views
import sys
sys.setcheckinterval(100000) # since we don't use threads, internal checks are no more required

import views

def start():
    evwsgi.start("", "8085")


    def index(environ, start_response):
        print "GET:", environ['fapws.uri']
        return views.index(environ, start_response)

    def mystatic(environ, start_response):
        return s(environ, start_response)

    evwsgi.wsgi_cb(("/", index))
    print "libev ABI version:%i.%i" % evwsgi.libev_version()

if __name__=="__main__":

Go web server

For Go I'm using the following script which is a collection of samples I've found on internet

package main

import (

func sayhelloName(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello world!") // send data to client side

func staticFile(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "page") // send data to client side

func main() {
        fs := http.FileServer(http.Dir("static"))
        http.Handle("/static/", http.StripPrefix("/static/", fs))
        http.HandleFunc("/", sayhelloName)       // set router
        err := http.ListenAndServe(":9090", nil) // set listen port
        if err != nil {
                log.Fatal("ListenAndServe: ", err)


Hello world

The first test is to return the simple "Hello World".

In both cases, I've asked ApacheBenchmark to perform 100.000 requests.

For 100.000 requests, the results are:


The memory values are:


Those results are un-expected. It means that Python with bunch of C code has the same performance of Go.

Let's see what will be the results with a small static file ans with a much bigger static file. This is a much representative test.

Small static file

The small file will be a file of 9,7kB. This is typically a css or an icon we can often see on web sites.

Still for 100.000 request, the results are:


The memory values are:


Those results are still amazing. Fapws is in fact better for such use case.

Big static file

The file will be a file of 2.1MB. This is typically a picture file we can see on web sites.

Still for 100.000 request, the results are:


For a concurrency of 1000, Go stopped working by saying: "too many open files, retrying in 5 ms"

The memory values are:


Those results are still amazing. Fapws is in fact better for such use case.


Surprisingly, Go is not better than Fapws. Moreover the memory foot print is quite bad.
But this last element could be improved. Indeed, after having spent some time this year at the Fosdem, I saw the following presentation. A novice like me in Go, will understand that memory could be drastically reduced, but need a certain expertise.

I think that the remaining test is to compare Fapws with Rust.

31, 32
displayed: 4081

What is the second letter of the word Moon?