Intro to GO performance

25 January 2017

Gediminas Morkevicius

Senior Gopher at, DATA-DOG

Who am I

The dude who codes go with ViM

Working at

Today

General Performance

It depends, can achieve close to C++ results in some cases where concurrency can be involved.
It also allows to manage the memory on your own. But again, it depends.

Compilation performance

This matters a lot, if you ever compiled large C++ projects.

jujud has 625 dependent packages and takes around 54 seconds to build on go 1.7

GOPATH=$(pwd) go list -f '{{ join .Deps "\n" }}' github.com/juju/juju/cmd/jujud | wc -l

What matters most

But you should know the boundaries of programming languages. What most you can expect from it.

Lets take a http server as an example

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/julienschmidt/httprouter"
)

func docs(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
    fmt.Fprintf(w, "v1 documentation")
}

func users(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
    fmt.Fprintf(w, "users: %s", ps.ByName("id"))
}

func main() {
    router := httprouter.New()
    router.GET("/v1", docs)
    router.GET("/v1/users/{id}", users)

    log.Fatal(http.ListenAndServe(":8080", router))
}

Performance

I will quote Rob Pike.

Fancy algorithms are slow when n is small, and n is usually small.
Fancy algorithms have big constants.
Until you know that n is frequently going to be big, don't get fancy.

Standard http handler to solve our problem

type Mux struct {
    // references to services
}

func (m *Mux) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    const users = "/v1/users/"
    switch {
    case req.URL.Path == "/v1":
        m.docs(w, req)
    case strings.Index(req.URL.Path, users) == 0:
        m.users(w, req, req.URL.Path[len(users):])
    default:
        http.NotFoundHandler().ServeHTTP(w, req)
    }
}
func (m *Mux) docs(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "v1 documentation")
}
func (m *Mux) users(w http.ResponseWriter, req *http.Request, id string) {
    fmt.Fprintf(w, "users: %s", id)
}
func main() {
    log.Fatal(http.ListenAndServe(":8080", &Mux{}))
} //end

GC performance

GC performance compared

I remember having 300ms pauses with versions before 1.5*.

Compared to other languages:

Examples are from https://github.com/spion/hashtable-latencies which measured large hashtable GC
performance in worst case. For typical programs these are better.

NOTE, go 1.8 devel was tested

Thank you

Gediminas Morkevicius

Senior Gopher at, DATA-DOG

Use the left and right arrow keys or click the left and right edges of the page to navigate between slides.
(Press 'H' or navigate to hide this message.)