Concurrency is built into Go itself, letting a program run many tasks at once without the overhead of OS threads. Goroutines execute those tasks; channels pass data between them safely.
A goroutine is a lightweight thread managed by the Go runtime. Prefixing a function call with go runs it concurrently in the background.
func say(s string) {
fmt.Println(s)
}
go say("world")
say("hello")Channels connect concurrent goroutines. make creates one, with the type it carries specified alongside chan.
messages := make(chan string)The arrow operator <- sends and receives values, pointing in the direction data flows: messages <- v sends, <-messages receives. Both operations block until the other side is ready, synchronizing goroutines without explicit locks.
go func() {
messages <- "ping"
}()
msg := <-messages
fmt.Println(msg)Running concurrent code can result in different output orders depending on system timing. However, channel synchronization guarantees that the main function won't exit until it receives the "ping" message.
$ go run concurrency.go
hello
world
ping