Concurrency

Goroutines and Channels

Harness Go's built-in concurrency with goroutines and channels.

Goroutines

A goroutine is a lightweight thread managed by the Go runtime. You can run thousands of goroutines concurrently.

Start a goroutine with the go keyword before a function call.

Channels

Channels are the pipes that connect goroutines. Send and receive values between goroutines.

  • ch <- value — send
  • value := <-ch — receive

WaitGroups

Use sync.WaitGroup to wait for a group of goroutines to finish.

Select

select is like a switch for channel operations. It blocks until one case is ready.

Example

go
package main

import (
    "fmt"
    "sync"
    "time"
)

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()  // decrement counter when done
    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Second)
    fmt.Printf("Worker %d done\n", id)
}

// Pipeline pattern with channels
func generate(nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        for _, n := range nums {
            out <- n
        }
        close(out)
    }()
    return out
}

func square(in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        for n := range in {
            out <- n * n
        }
        close(out)
    }()
    return out
}

func main() {
    // Basic goroutine with WaitGroup
    var wg sync.WaitGroup
    for i := 1; i <= 3; i++ {
        wg.Add(1)
        go worker(i, &wg)
    }
    wg.Wait()
    fmt.Println("All workers done")

    // Channel pipeline
    nums := generate(2, 3, 4, 5)
    squares := square(nums)
    for n := range squares {
        fmt.Print(n, " ")  // 4 9 16 25
    }
    fmt.Println()

    // Select with timeout
    ch := make(chan string)
    go func() {
        time.Sleep(2 * time.Second)
        ch <- "result"
    }()

    select {
    case res := <-ch:
        fmt.Println("Got:", res)
    case <-time.After(1 * time.Second):
        fmt.Println("Timeout!")
    }
}
Try it yourself — GO