You are viewing a free preview of this lesson.
Subscribe to unlock all 10 lessons in this course and every other course on LearningBro.
Concurrency is one of Go's greatest strengths. Go was designed from the ground up to make concurrent programming simple and efficient. The key primitives are goroutines (lightweight threads) and channels (typed communication pipes).
A goroutine is a lightweight thread managed by the Go runtime:
func sayHello() {
fmt.Println("Hello from goroutine!")
}
func main() {
go sayHello() // launch a goroutine
time.Sleep(time.Second) // wait for it to finish (crude approach)
}
| Property | Description |
|---|---|
| Cost | ~2 KB initial stack (grows as needed) — much cheaper than OS threads |
| Scheduling | Managed by the Go runtime, not the OS |
| Scalability | Easily run millions of goroutines |
| Launch syntax | go functionCall() |
| Return values | Cannot return values directly — use channels |
go func() {
fmt.Println("Anonymous goroutine")
}()
go func(msg string) {
fmt.Println(msg)
}("Hello")
Channels are typed conduits for communication between goroutines:
ch := make(chan string) // unbuffered channel of strings
go func() {
ch <- "hello" // send to channel
}()
msg := <-ch // receive from channel
fmt.Println(msg) // "hello"
| Type | Syntax | Behaviour |
|---|---|---|
| Unbuffered | make(chan T) | Sender blocks until receiver is ready |
| Buffered | make(chan T, size) | Sender blocks only when buffer is full |
| Send-only | chan<- T | Can only send |
| Receive-only | <-chan T | Can only receive |
ch := make(chan int, 3) // buffer size 3
ch <- 1 // does not block
ch <- 2 // does not block
ch <- 3 // does not block
// ch <- 4 // would block — buffer is full
fmt.Println(<-ch) // 1
fmt.Println(<-ch) // 2
ch := make(chan int)
go func() {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch) // signal that no more values will be sent
}()
// Range over a channel — loops until the channel is closed
for v := range ch {
fmt.Println(v) // 0, 1, 2, 3, 4
}
| Operation | nil Channel | Closed Channel | Open Channel |
|---|---|---|---|
| Send | Blocks forever | Panic | Sends (may block) |
| Receive | Blocks forever | Returns zero value + false | Receives (may block) |
| Close | Panic | Panic | Closes |
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
results <- j * 2 // process the job
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// Fan-out: 3 workers reading from the same jobs channel
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
// Send jobs
for j := 1; j <= 9; j++ {
jobs <- j
}
close(jobs)
// Fan-in: collect results
for r := 1; r <= 9; r++ {
fmt.Println(<-results)
}
}
Subscribe to continue reading
Get full access to this lesson and all 10 lessons in this course.