Language path · Go · 49 layers

Go: types, goroutines, and the GMP pipeline

package main wraps the mux. The mux calls Handler. Handler may go a worker. The contract — types, slices, errors — links into Handler. Pan down: concurrency catalog, then the scheduler as a pipeline, with the traps crossed out. Click Handler, Accept, or nil interface.

Click a shape or a question

Questions this tree answers

A request · one G per accept · cancel is not optional

Types · slices · errors
types · pointers
slices · maps
errors · defer · modules
main → mux → handler
Operation
Library
Receivers · interfaces
GMP · one G per request
Goroutine stack
Heap / escape
Slice header
Interface word
GC / reachability
Concurrency catalog
go · bound
channels · select
context · sync
generics · io
Scheduler — pipeline and traps
G created → drain
don’t · advanced last
process wrapsoperationlibrarydon’t extendmust still enddon’t callvs copysatisfiesruns onholdsescapeif unreachablevs slackvs one wordDoes not: subclassAllows: write responseAllows: go after commitAllows: library Save3. types2. errorsslicesAllows: pointer receiverDoes not: mutate a copyAllows: go f()Does not: park forever
entrypackage main · func main
  • runtime dials after init
rejectedclass extends Server
  • is-a · not the model
  • don’t subclass
routerServeMux
  • patterns · two children
  • Handler + library · not nested
operationServeHTTP
  • decode · save · write
  • one G for this request
writeWriteHeader
  • status then body
  • no extra G
side pathgo fanout
  • after commit
  • must watch ctx
libraryinvoice.Save
  • domain · not main
  • tests import this
  • sibling of Handler, not a child
runtimeruntime calls main()
  • after init
  • you do not dial
wrongmain() yourself
  • not importable
  • tests call the library
zero0 · false · "" · nil
  • declared is valid
  • nil map write panics
declarevar x T · x := v
  • := needs a new name
  • inner err shadows
address*T · &x
  • share vs copy
  • nil deref panics
allocmake vs new
  • make: slice/map/chan
  • new: *zero
recordtype Invoice struct
  • keyed literal
  • copy on assign
  • methods hang off this
headerslice { ptr, len, cap }
  • array is elsewhere
  • reslice aliases
growa = append(a, x)
  • take the return
  • alias until realloc
value[N]T copies
  • N is in the type
  • API wants a slice
hashmake(map[K]V)
  • nil write panics
  • no concurrent write
bytesstring · rune · byte
  • len is bytes
  • range is runes
  • immutable
returns(T, error)
  • error last
  • closures share the var
LIFOdefer cancel()
  • args now · call later
  • not per-iteration
valueif err != nil
  • not an exception
  • visible path
chainfmt.Errorf("%w")
  • Is / As walk
  • %v severs
impossiblepanic / recover
  • not HTTP 400
  • recover in defer
APIExport = capital
  • directory is package
  • init is a trap
tableTestFoo(t *testing.T)
  • t.Run · -race
  • import the library
identitygo.mod
  • path is the name
  • go.sum · /v2 is a new module
pointer recvfunc (c *Cart) Add
  • mutates same Cart
  • one method set
value recvfunc (c Cart) Total
  • copy · mutation dies
  • keep * if any method needs *
has-aembed http.Handler
  • promotion, not is-a
contracttype Store interface
  • implicit · keep it small
traperr = (*T)(nil)
  • itab set · not nil
narrowv, ok := x.(T)
  • errors.As on wraps
GG · goroutine
  • stack · parked or running
  • not an OS thread
MM · OS thread
  • must hold a P to run Go
  • syscall may stick the M
PP · processor
  • holds the runqueue
  • GOMAXPROCS is not a G cap
stackServeHTTP frame
  • locals die on return
  • unless they escape
  • cheap path
heap*Invoice escaped
  • address needed later
  • go build -gcflags=-m
  • GC work
headerbody { ptr, len, cap }
  • three words on the stack
  • array on the heap
  • reslice aliases
two wordserror { itab, data }
  • dynamic type + value
  • nil trap = itab set
  • indirect call
eligibleunreachable → GC
  • no path from roots
  • parked G still roots
measurepprof heap · goroutine
  • names the live set
  • don’t guess GOGC
startgo f()
  • new G · small stack
  • must be able to end
boundworker pool
  • SetLimit
  • ceiling around Gs
joinAdd · go · Wait
  • Add before go
  • defer Done
grouperrgroup
  • first error
  • cancels siblings
  • WaitGroup + ctx
meetmake(chan T)
  • send waits for receive
  • happens-before
slackmake(chan T, n)
  • full = backpressure
  • huge n = leak
endclose(ch) · range
  • sender closes
  • double close panics
waitselect { Done }
  • random among ready
  • always ctx.Done
proverbShare by communicating
  • pass ownership on a chan
  • mutex if already shared
first argctx context.Context
  • deadline · cancel
  • don’t store on the server
lockmu.Lock()
  • defer Unlock
  • don’t copy · hold short
wordatomic.Int64
  • one word
  • not two fields
oncesync.Once
  • init, not per request
  • panic counts as done
type paramfunc Max[T cmp.Ordered]
  • constraints are interfaces
  • not a one-type wrapper
  • compile time
bytesio.Reader · Writer
  • Read([]byte)
  • compose wrappers
  • Copy · LimitReader
  • EOF is done
1 createNew G
  • go f() · small stack
2 runqueueP local runqueue
  • ready Gs
3 executeM runs the G
  • ServeHTTP here
4 syscallSyscall · P stolen
  • netpoll parks G
5 stealWork steal
  • idle P takes half
  • does not split a tight loop
6 preemptPreempt the G
  • fairness · lock still held
parkPark on chan / select
  • off the runqueue
  • must wake · ctx.Done
drainShutdown(ctx)
  • stop accept · budget
  • no naked Exit
mapG ≈ goroutine · M ≈ thread · P ≈ runqueue
  • create → runqueue → execute → park → drain
  • GOMAXPROCS caps Ps, not Gs
forbiddengo in a million loop
  • no ceiling
  • pool instead
forbiddenWithCancel without defer
  • leaks the child
  • timer may linger
undefinedtwo Gs · one word · no sync
  • go test -race
  • map concurrent write panics
escape hatchunsafe.Pointer
  • uintptr is not a pointer
  • almost never in Handler
runtime typesreflect.Type · Value
  • json lives here
  • not the hot loop
72%

Click a box · three arrows off a layer are what it allows

What Go is