concurrency
2w ago

Synchronization and Communication

5 views • 0 upvotes

Channels (Recommended)

Channels are Go's preferred way to communicate between goroutines.

Unbuffered Channels

go
ch := make(chan int) // Synchronous communication

// Sender blocks until receiver receives
go func() {
    ch <- 42 // Send (blocks until received)
}()

value := <-ch // Receive (blocks until sent)
fmt.Println(value) // 42
Visualization:
code
Goroutine 1          Channel          Goroutine 2
    │                   │                   │
    │  ch <- 42         │                   │
    │──────────────────►│                   │
    │  (blocks)         │                   │
    │                   │  value := <-ch    │
    │                   │◄──────────────────│
    │  (unblocks)       │  (receives 42)    │
    │                   │                   │

Buffered Channels

go
ch := make(chan int, 3) // Buffer size 3

// Can send 3 values without blocking
ch <- 1
ch <- 2
ch <- 3
// ch <- 4 // This would block!

fmt.Println(<-ch) // 1
fmt.Println(<-ch) // 2
fmt.Println(<-ch) // 3

Channel Directions

go
// Send-only channel
func send(ch chan<- int) {
    ch <- 42
    // value := <-ch // Compile error!
}

// Receive-only channel
func receive(ch <-chan int) {
    value := <-ch
    // ch <- 42 // Compile error!
}

func main() {
    ch := make(chan int)
    go send(ch)
    go receive(ch)
}

Select Statement

go
func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)
    
    go func() {
        time.Sleep(1 * time.Second)
        ch1 <- "from ch1"
    }()
    
    go func() {
        time.Sleep(2 * time.Second)
        ch2 <- "from ch2"
    }()
    
    for i := 0; i < 2; i++ {
        select {
        case msg1 := <-ch1:
            fmt.Println(msg1)
        case msg2 := <-ch2:
            fmt.Println(msg2)
        case <-time.After(3 * time.Second):
            fmt.Println("timeout")
        }
    }
}

Mutexes (When Needed)

Use mutexes for protecting shared state:
go
type SafeCounter struct {
    mu    sync.Mutex
    count map[string]int
}

func (c *SafeCounter) Inc(key string) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.count[key]++
}

func (c *SafeCounter) Value(key string) int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.count[key]
}

func main() {
    counter := SafeCounter{count: make(map[string]int)}
    var wg sync.WaitGroup
    
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            counter.Inc("key")
        }()
    }
    
    wg.Wait()
    fmt.Println(counter.Value("key")) // 1000
}

Was this helpful?

Difficulty & Status

easy
Lvl. 2
Community Verified
Progress: 11%
Answered by: shubham vyasPrev TopicNext Topic