Go routine and channel internals
- https://internals-for-interns.com/posts/understanding-go-runtime/
- https://www.cs.cmu.edu/~crary/819-f09/Hoare78.pdf
- https://docs.google.com/document/u/0/d/1TTj4T2JO42uD5ID9e89oa0sLKhJYD0Y_kqxDv3I3XMw/mobilebasic#heading=h.mmq8lm48qfcw
- https://blog.bullgare.com/2022/12/gos-concurrency-and-channel-internals/
- https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part1.html
- https://nghiant3223.github.io/2025/04/15/go-scheduler.html
- https://nghiant3223.github.io/2025/06/03/memory_allocation_in_go.html
- https://datadoghq.dev/go-profiler-notes/mental-model-for-go/goroutine-scheduler.html
- https://binarymusings.org/posts/golang/golang_epoll/
- Scaling Go to 192 cores for Heavy IO https://jazco.dev/2024/01/10/golang-and-epoll/
- GOMAXPROCS, epoll/kqueue, and Scheduler-Level Tuning https://goperf.dev/02-networking/a-bit-more-tuning/
- creation of the
hchanstruct at channel creation. A heap allocated circular buffer protected by a mutex.sendxandrecvx. The reference to thishchanstruct is maintained in the goroutine stack - We have a
sendqand arecvqthat are doubly linked lists. The data type is a waitq. The buffer points to a circular queue. The each data type in this LL is a sudog type and has an unsafe pointer to an element. This is the memory address of a variable. This also holds g type which is a reference object or the identity of the go routine holding data about waiting, the status of the routine
Buffered channel
- our circular queue is the
bufwhere we write to the circular queue ch <- 3we push a value into the channel. In the case when its full, we create asudogobject as we cannot write to the channel buffer. Thissudogobject is placed in thesendqDLL and this is our queue for items that are trying to be written to the buffer.- The go routine calls
goparkand the go scheduler changes the state of the go routine to waiting. result <- chwill read from thebufcircular queue.
ch <- 1
ch <- 2
ch <- 3 // this is pushed to sendq
res <- ch // 1
// sendq value of 3 pushed into queue
res <- ch // 2
res <- ch // 3
res <- ch // we now call gopark as there is nothign in the buf. We have a sudog allocated and puhsed into the recvq- when a sender now publishes an element into the channel, instead of writing to the
bufwe directly do amemcopy()to the recv. We directly copy to goroutine stack and we do not touch the circular queuebuf
func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
// snip
if c.dataqsiz == 0 {
if raceenabled {
racesync(c, sg)
}
if ep != nil {
// copy data from sender
recvDirect(c.elemtype, sg, ep)
}
// snip
}
// snip
}
func recvDirect(t *_type, sg *sudog, dst unsafe.Pointer) {
// dst is on our stack or the heap, src is on another stack.
// The channel is locked, so src will not move during this
// operation.
src := sg.elem.get()
typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.Size_)
memmove(dst, src, t.Size_)
}Unbuffered channel flow
- we have direct stack to stack copy. We do not have a circular queue holding elements being sent
Select statement
select {
case <-ch1:
case <-ch2:
default: // default non blocking exit
}
select { // blocking multi-select
case <-ch1:
case <-ch2:
}Patterns
- actor-styled ownership pattern
- shared state pattern
- worker pool pattern for bounded concurrency
- fan in and out
- How Go (Golang) Works — A Deep Dive into Runtime Internals muratdemirci.com.tr
- Go Concurrency Patterns: Context go.dev
- Go Concurrency Patterns: Pipelines and cancellation go.dev
- developer.hashicorp.com rollback manager for cleanup
- Leaking goroutines by Karl Seguin openmymind.net
- Goroutine Leaks - The Forgotten Sender ardanlabs.com
- Proposal: Goroutine leak detection via garbage collection go.googlesource.com
- boundary hashicorp architecture
- https://www.ibm.com/think/topics/control-plane-vs-data-plane
- Different planes (control, data and management plane) in systems developer.hashicorp.com
- Having a separate plane for blast radius, network reach, horz scaling, upgrade cadence, multi tenancy of networks
- Overkill when we have single tenant, stateless apis, when latency to control plane is acceptable
- Designing resilient systems by IBM and Hashicorp https://developer.hashicorp.com/well-architected-framework/design-resilient-systems
dbw by hashicorp (https://github.com/hashicorp/go-dbw) as a database wrapper in boundary
- boundary uses a public key infra (PKI) https://www.hashicorp.com/en/blog/what-is-public-key-infrastructure-pki
- mutual TLS https://www.cloudflare.com/learning/access-management/what-is-mutual-tls/
- https://www.cloudflare.com/learning/access-management/what-is-mutual-authentication/
- More on Zero Trust security https://www.cloudflare.com/learning/security/glossary/what-is-zero-trust/
- Atomic pointers in golang https://pkg.go.dev/sync/atomic#Pointer
- https://groups.google.com/g/golang-dev/c/SBmIen68ys0/m/WGfYQQSO4nAJ?pli=1
- https://victoriametrics.com/blog/go-sync-map/
io.Copyin goroutine to prevent blocking https://stackoverflow.com/questions/62522276/io-copy-in-goroutine-to-prevent-blocking- https://eklitzke.org/goroutines-nonblocking-io-and-memory-usage
- Chapter 8. Goroutines and Channels - Shichao’s Notes https://notes.shichao.io/gopl/ch8/
- https://victoriametrics.com/blog/go-io-reader-writer/
- in process grpc-gateway + bufconn to remove secondary network hop between HTTP and gRPC handler.
- https://grpc-ecosystem.github.io/grpc-gateway/