This article is a summary of what I learnt from Björn Rabenstein’s talk on this topic.

You can check out the whole video below

#1 Measure Everything

Don’t optimise prematurely. Always measure everything to identify the right code paths that need a fix.

Tools : go test, pprof, go-torch

#2 Don’t let GC fool you

Go GC doesn’t do stop-the-world scenarios a lot anymore but it still does the work in the background which may lead to low GC pause time but higher micro service latencies.

#3 Avoid allocations

Code with care. Don’t reallocate every value in a loop. Use buffers and sync.Pool wherever possible rather than creating a new byte array every time.

#4 Avoid heap fragmentation

Check for the difference between resident memory (the pages which actually reside in physical memory) and the memory used by your program. If the difference is large and growing, you are suffering from heap fragmentation.

Try to allocate as many fixed size objects you can, rather than any random size. e.g. fixed size byte arrays

#5 Don’t use Mutex

Mutexes are slow (~100 ns per op)

Communicate using channels wherever you can rather than by sharing memory. Only use mutex, when you really need a low level communication.

#6 Use int as keys instead of strings in Map

For every lookup and update, hash needs to be computed for a string key which is not O(1) w.r.t. string length.

Hence, it’s better to use a int as key. If you really need strings, use a simpler hash algorithm (e.g. fnv64a) which may lead to more hash collisions but provide better performance for general cases.

#7 Abstractions are costly

If you really don’t need most of the functionalities of a heavy interface (e.g. Hash) , you can code your interface or use concrete types in functions. It’ll be much faster

✉️ Subscribe to CodeBurst’s once-weekly Email Blast, 🐦 Follow CodeBurst on Twitter, view 🗺️ The 2018 Web Developer Roadmap, and 🕸️ Learn Full Stack Web Development.