{"id":18292503,"url":"https://github.com/marclop/ultimatego-notes","last_synced_at":"2026-01-28T17:03:52.358Z","repository":{"id":81024910,"uuid":"135993476","full_name":"marclop/ultimatego-notes","owner":"marclop","description":"Notes from attending Ultimate Go Gophercon2018 workshop (short version)","archived":false,"fork":false,"pushed_at":"2018-11-22T12:41:44.000Z","size":9,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-29T15:15:25.340Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marclop.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-06-04T08:20:49.000Z","updated_at":"2018-11-22T12:42:31.000Z","dependencies_parsed_at":"2023-03-23T00:12:57.397Z","dependency_job_id":null,"html_url":"https://github.com/marclop/ultimatego-notes","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/marclop/ultimatego-notes","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marclop%2Fultimatego-notes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marclop%2Fultimatego-notes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marclop%2Fultimatego-notes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marclop%2Fultimatego-notes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marclop","download_url":"https://codeload.github.com/marclop/ultimatego-notes/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marclop%2Fultimatego-notes/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28847057,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T15:15:36.453Z","status":"ssl_error","status_checked_at":"2026-01-28T15:15:13.020Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T14:18:20.895Z","updated_at":"2026-01-28T17:03:52.330Z","avatar_url":"https://github.com/marclop.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ultimate Go\n\nhttps://github.com/ardanlabs/gotraining/blob/master/topics/courses/go/README.md\n\n## Disclaimer\n\nAll the information below are **my personal notes** from attending William Kennedy's adapted Ultimate Go (1 day length) workshop at Gophercon EU 2018 in Iceland. Some of the information might be imprecise and even wrong, so make sure to fact check what's written here and push any changes as you see fit.\n\nThese are rough notes and do not reflect the quality and content of the workshop that was delivered.\n\nI highly encourage anyone that stumbles upon this repo to take the full [Ultimate Go](https://www.ardanlabs.com/ultimate-go).\n\n## Table of contents\n\n- [Ultimate Go](#ultimate-go)\n    - [Disclaimer](#disclaimer)\n    - [Table of contents](#table-of-contents)\n    - [Performance Focus factors](#performance-focus-factors)\n    - [Language Mechanics](#language-mechanics)\n        - [Memory structure](#memory-structure)\n        - [Goroutines (Coroutines really, G is for Go)](#goroutines-coroutines-really--g-is-for-go)\n    - [Value semantics](#value-semantics)\n        - [Pros](#pros)\n        - [Cons](#cons)\n    - [Pointer semantics](#pointer-semantics)\n        - [Pros](#pros)\n        - [Cons](#cons)\n        - [Mechanics](#mechanics)\n            - [Good](#good)\n            - [Bad](#bad)\n    - [Moar about the stack](#moar-about-the-stack)\n    - [HEAP](#heap)\n    - [Data structures](#data-structures)\n    - [Memory structure](#memory-structure)\n            - [Example of multiple runs](#example-of-multiple-runs)\n    - [Semantics](#semantics)\n    - [Decoupling](#decoupling)\n- [Concurrency](#concurrency)\n    - [Types of work by threads](#types-of-work-by-threads)\n    - [Switching from one thread to another](#switching-from-one-thread-to-another)\n    - [Go and Scheduling / Concurrency](#go-and-scheduling---concurrency)\n\n## Performance Focus factors\n\n1. Latency:\n    * I/O.\n    * Network.\n    * Timeouts.\n\n2. Garbage collection\n    * Generate the right type of Garbage.\n\n3. Accessing Data\n\n4. Algorithm efficiency\n    * Machines are already very powerful, we can be less optimized today.\n\n## Language Mechanics\n\n* [Pointers](https://github.com/ardanlabs/gotraining/blob/master/topics/go/language/pointers/README.md)\n\n\n### Memory structure\n\nData Segment\nStacks\nHeap\n\n### Goroutines (Coroutines really, G is for Go)\n\nSee: https://play.golang.org/p/JJMHWiZ9h9\n\nGlossary:\n    * `AF`: Active Frame.\n    * `Semantics`: Behaviour.\n    * `Mechanics`: How it works.\n\n* Have their own resizeable stack, starting at 2K.\n    * Segmentation for safety.\n\n* Calling (executing) a function moves the AF to nother part of the stack.\n\n\nAny memory below the active frame has no integrity and is stale.\n\n// TODO: Diagram stack.\n\nPointers are a special variable type 4 to 8 bytes depending on the architecture.\n`func increment(inc *int)` is still a pass by value, the value is the pointer address.\n\n## Value semantics\n\n### Pros\n    * Immutability.\n    * No side effects.\n    * Allocations happen on the stack (Free, sorta).\n\n### Cons\n    * Efficiency (Multiple copies of the data on multiple frames).\n\n## Pointer semantics\n\n### Pros\n    * Efficiency (Easy to maintain consistency).\n\n### Cons\n    * Side effects (Worsened in concurrent programs).\n    * Allocations on the Heap.\n\n\n### Mechanics\n\nhttps://play.golang.org/p/sRcPykfoi1d\n\nAllocations are only counted for\n\nCall func =\u003e Initialize Stack =\u003e Finish func =\u003e Switch AF =\u003e Invalidates stacks below the AF.\n\n\nGo compiler performs Static code analysis:\n    * Escape Analysis (Any memory initialized down the stack is shared up).\n\nAny shared variables upwards on the call stack will be **allocated** in the heap.\nAvoid pointer semantics on construction unless you return it directly or construct it on the pass val.\n\n\n####  Good\n```go\nfunc createUserV2() *user {\n\tu := user{\n\t\tname:  \"Bill\",\n\t\temail: \"bill@ardanlabs.com\",\n\t}\n\n\tprintln(\"V2\", \u0026u)\n\n\treturn \u0026u\n}\n```\n\n####  Bad\n```go\nfunc createUserV2() *user {\n\tu := \u0026user{\n\t\tname:  \"Bill\",\n\t\temail: \"bill@ardanlabs.com\",\n\t}\n\n\tprintln(\"V2\", u)\n\n\treturn u\n}\n\n// OR\n\nfunc createUserV2() user {\n\tu := \u0026user{\n\t\tname:  \"Bill\",\n\t\temail: \"bill@ardanlabs.com\",\n\t}\n\n\tprintln(\"V2\", u)\n\n\treturn *u\n}\n```\n\n**Rule of thumb: Use semantics on return to hint what kind of value you're returning**\n\n\n**THIS IS SO AWESOME**\nOptimizing for performance, use `-gcflags \"-m -m\"`: will output reasoning behind escape analysis.\n\nEscape analysis is about moving stuff from the **Stack** to the **Heap**.\nValue semantics should be the default option because **allocations hurt** (Even tho more performant).\n\nThe size of Stacks are set in stone and are known at compile time.\nIf the compiler does not know the size of something it has to move it to the **heap**.\n\n## Moar about the stack\n\nhttps://play.golang.org/p/tpDOwBCvqW\n\nGoroutines are awesome cause they have a 2K stack.\n\nThey are resizeable (growable).\n\n1. Run out of space in the stack.\n2. Create a new (bigger) memory space.\n\nIn the example below we can the memory positions of a string variable hello that exists\nin the main.main goroutine stack and how the memory addresses change as the stakc is resized.\n\n```\n0 0x1044dfa0 HELLO\n1 0x1044dfa0 HELLO\n2 0x10455fa0 HELLO\n3 0x10455fa0 HELLO\n4 0x10455fa0 HELLO\n5 0x10455fa0 HELLO\n6 0x10465fa0 HELLO\n7 0x10465fa0 HELLO\n8 0x10465fa0 HELLO\n9 0x10465fa0 HELLO\n```\n\nThus, it creates new memory addresses to contain the contents of the pointers, thus new pointer addresses.\n\n**IN Go, the stack is isolated to that goroutine, and variables and pointers in the stack are self contained.**\n\nWhen memory is shared, the variables (Addr) move to the stack (See upwards behaviour).\n\nWhen deciding to share memory by pointers, make sure that your usecase actually needs it. i.e. Data integrity.\n\n## HEAP\n\nhttps://github.com/ardanlabs/gotraining/blob/master/topics/go/language/pointers/README.md#garbage-collection\n\nConcurrent, Mark \u0026 Sweep, Garbage collector.\n\n1. Value semantics.\n2. Pointer semantics.\n\nGo tries to keep resource utilisation at the minimum. Go asks:\n\n*What's the minimum Heap Size I can have so I can run efficiently (at a reasonable pace) below 100 microseconds.*\n\nCollector is allowed to use up to 25% of total CPU capacity on resource contention.\n\nTO stop the world, you've got to stop all of the goroutines and bring them to a safe point the only current mechanism\nto do so is stopping them at function calls (up to 1.10).\n\nTheres 2 stop the world points:\n\n1. Turning the Write barrier on.\n2. Scan stacks to the Active Frames.\n3. Everything starts white.\n4. Things move to grey and get marked either White or Black ocne the usage is decided.\n5. Once there's no more Grey items, Mark phase is done\n6. SWEEP =\u003e Reclaim WHITE objects not in use.\n7. OFF =\u003e GC Disabled.\n\n\nWhite, Gray, Black.\n\nonce we're done, everything is White or Black.\n\nBlack means the _object_ is used.\nWhite means the _object_ is safe to be swept (deleted).\n\nLess is more.\n\n### Example heap distribution\n\n==============  4 MB\n\n  Transient ^\n\n--------------  2 MB\n\n  Permanent\n\n==============\n\n\n## Data structures\n\n### Arrays\n\nhttps://github.com/ardanlabs/gotraining/blob/master/topics/go/language/arrays/README.md\n\nhttps://youtu.be/WDIkqP4JbkE?t=1129 Small is fast.\n\n\n## Memory structure\n\nMain memory is broken into cache lines.\nCache lines =\u003e 64 bytes\n\n\nCreate code that has predictable access patterns to memory.\n\nPrefetches.\nPrefetches read your program's access to memory and try to predict the access pattern to memory.\n\nArrays and slices give us contiguous strides of access to the memory.\n\nArrays are the most important data structure there is today.\n\nSlice is the most important data structure in Go.\n\nMost of the time the slice is the right data structure.\n\n\nTLB Cache.\n\nWhen a program comes up is given a full map of virtual memory.\n\nMemory is managed in Memory Pages.\n\n![](https://drawings.jvns.ca/drawings/malloc.svg)\n\n#### Example of multiple runs\n\n```\nElements in the link list 4194304\nElements in the matrix 4194304\ngoos: darwin\ngoarch: amd64\npkg: github.com/ardanlabs/gotraining/topics/go/testing/benchmarks/caching\nBenchmarkLinkListTraverse-8   \t    1000\t   6767661 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLinkListTraverse-8   \t    1000\t   7207894 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLinkListTraverse-8   \t     500\t   6474441 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkColumnTraverse-8     \t     500\t  11459971 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkColumnTraverse-8     \t     500\t  11157890 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkColumnTraverse-8     \t     500\t  10665148 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkRowTraverse-8        \t    1000\t   3959297 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkRowTraverse-8        \t    1000\t   4000582 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkRowTraverse-8        \t    1000\t   3924701 ns/op\t       0 B/op\t       0 allocs/op\nPASS\nok  \tgithub.com/ardanlabs/gotraining/topics/go/testing/benchmarks/caching\t56.891s\n\n```\n\nhttps://github.com/ardanlabs/gotraining/tree/master/topics/go#data-oriented-design\n\n\nTODO: Watch:\n* [CPU Caches and Why You Care](https://www.youtube.com/watch?v=WDIkqP4JbkE)\n* [NUMA Deep Dive](http://frankdenneman.nl/2016/07/06/introduction-2016-numa-deep-dive-series/)\n* [Data-Oriented Design and C++](https://www.youtube.com/watch?v=rX0ItVEVjHc)\n\nRead [Data Oriented Design](https://github.com/ardanlabs/gotraining/blob/master/topics/go/language/arrays/README.md#data-oriented-design)\n\n\n## Semantics\n\nDesigning for value or pointer semantics\n\nIf the alteration changes the core value of what you're changing you want to return a new value without altering the state.\n\nIf the alteration modifies a property but doesn't modify the underlying state or meaning of the data then you want to youse pointer semantics.\n\n**Avoid mixing semantics in different types**\n\nNever go from pointer to value semantics, it causes SHIT TO GO DOWN.\n\n\n## Decoupling\n\nMake the choice between Performance and decoupling. Interfaces provide double indirection which causes the escape\nanalysis to move the types that use the interfaces to the heap even if they're not escaping.\n\n\n# Concurrency\n\nThread states\n\n* Running (Or executing).\n* Runnable (requesting CPU time).\n* Waiting (Lot of substatuses).\n\n## Types of work by threads\n\n* CPU Bound work: Thread never goes into waiting state.\n* I/O Bound work: Threads go back and forth from Running to Runnable / Waiting.\n\n## Switching from one thread to another\n\n* Context switches: expensive.\n* Less is more, less threads, each thread gets more time.\n* Non deterministic switches: Cannot make assumptions in the code.\n\n## Go and Scheduling / Concurrency\n\nGo is a cooperative scheduler.\n`runtime` does the cooperation.\n\n\n```go\n// Pprofs to stdout, so if you have any info going to standard out already\n// Make sure to point it to some other io.Writer.\npprof.StartCPUProfile(os.Stdout)\ndefer pprof.StopCPUProfile()\n```\n\n```shell\n$ ./trace \u003e p.out\n$ go tool pprof p.out\n(pprof) list find\n(pprof) web list find\n(pprof) top 40 -cum\n(pprof) list \u003cfunction name\u003e\n```\n\n\n### Trace\n\n```go\n// Traces out to stdout, so if you have any info going to standard out already\n// Make sure to point it to some other io.Writer.\ntrace.Start(os.Stdout)\ndefer trace.Stop()\n```\n\n\n```shell\n# Opens up\n$ go tool trace t.out\n```\n\n\n### Benchmarks\n\n// Add memory profile\n```shell\n-memprofile p.out\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarclop%2Fultimatego-notes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarclop%2Fultimatego-notes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarclop%2Fultimatego-notes/lists"}