Goroutines and Channels

Concurrent programming with goroutines and channel communication

#goroutines #channels #concurrency #async

Goroutines and Channels

Go's approach to concurrent programming using lightweight goroutines and channels.

Basic Goroutine

package main

import (
    "fmt"
    "time"
)

func sayHello() {
    fmt.Println("Hello from goroutine!")
}

func main() {
    go sayHello()  // Run in background
    time.Sleep(time.Second)  // Wait for goroutine
    fmt.Println("Main function")
}

Anonymous Goroutine

func main() {
    go func() {
        fmt.Println("Anonymous goroutine")
    }()

    time.Sleep(time.Second)
}

Basic Channel

func main() {
    messages := make(chan string)

    go func() {
        messages <- "Hello"  // Send to channel
    }()

    msg := <-messages  // Receive from channel
    fmt.Println(msg)
}

Buffered Channels

func main() {
    messages := make(chan string, 2)  // Buffer of 2

    messages <- "Hello"
    messages <- "World"
    // Would block: messages <- "!"  // Buffer full

    fmt.Println(<-messages)  // Hello
    fmt.Println(<-messages)  // World
}

Channel Synchronization

func worker(done chan bool) {
    fmt.Println("Working...")
    time.Sleep(time.Second)
    done <- true  // Signal completion
}

func main() {
    done := make(chan bool)
    go worker(done)

    <-done  // Wait for completion
    fmt.Println("Done!")
}

Channel Direction

// Send-only channel
func sender(ch chan<- string) {
    ch <- "message"
}

// Receive-only channel
func receiver(ch <-chan string) {
    msg := <-ch
    fmt.Println(msg)
}

func main() {
    ch := make(chan string)
    go sender(ch)
    receiver(ch)
}

Range Over Channel

func main() {
    numbers := make(chan int)

    go func() {
        for i := 0; i < 5; i++ {
            numbers <- i
        }
        close(numbers)  // Close when done
    }()

    for num := range numbers {
        fmt.Println(num)  // 0, 1, 2, 3, 4
    }
}

Select Statement

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)

    go func() {
        time.Sleep(time.Second)
        ch1 <- "one"
    }()

    go func() {
        time.Sleep(2 * time.Second)
        ch2 <- "two"
    }()

    for i := 0; i < 2; i++ {
        select {
        case msg1 := <-ch1:
            fmt.Println("Received", msg1)
        case msg2 := <-ch2:
            fmt.Println("Received", msg2)
        }
    }
}

Worker Pool Pattern

func worker(id int, jobs <-chan int, results chan<- int) {
    for job := range jobs {
        fmt.Printf("Worker %d processing job %d\n", id, job)
        time.Sleep(time.Second)
        results <- job * 2
    }
}

func main() {
    jobs := make(chan int, 100)
    results := make(chan int, 100)

    // Start 3 workers
    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }

    // Send 5 jobs
    for j := 1; j <= 5; j++ {
        jobs <- j
    }
    close(jobs)

    // Collect results
    for a := 1; a <= 5; a++ {
        <-results
    }
}

Timeout with Select

func main() {
    ch := make(chan string)

    go func() {
        time.Sleep(2 * time.Second)
        ch <- "result"
    }()

    select {
    case res := <-ch:
        fmt.Println(res)
    case <-time.After(1 * time.Second):
        fmt.Println("Timeout!")
    }
}

Non-Blocking Channel Operations

func main() {
    messages := make(chan string)

    select {
    case msg := <-messages:
        fmt.Println("Received:", msg)
    default:
        fmt.Println("No message available")
    }
}

WaitGroup for Synchronization

import "sync"

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()

    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Second)
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    var wg sync.WaitGroup

    for i := 1; i <= 3; i++ {
        wg.Add(1)
        go worker(i, &wg)
    }

    wg.Wait()  // Wait for all goroutines
    fmt.Println("All workers done")
}

Discover another handy tool from EditPDF.pro