The goroutine model
Goroutines are tiny (a few KB of stack) and multiplexed onto OS threads:
for i := 0; i < 1000; i++ {
go doWork(i)
}
Thousands of goroutines run at once. The runtime decides how many threads back them, you write concurrency without managing threads.
Data races
Sharing memory without coordination causes races:
var count int
go func() { count++ }()
count++ // race!
Use sync/atomic or a sync.Mutex to protect shared state. Run with -race to catch problems in testing.