Skip to content

Channels

Channel Basics

  • create a channel with make command
  • strong typed make(chan int)
  • send and receive a message to and from an channel using arrow syntax
  • send: ch <- val
  • receiveL val := <-ch
  • Can have multiple senders and receivers
    package main
    
    import (
        "fmt"
        "sync"
    )
    
    var wg = sync.WaitGroup{}
    
    func main() {
        ch := make(chan int)
        wg.Add(2)
        go func() {
            i := <-ch
            fmt.Println(i)
            wg.Done()
        }()
        go func() {
            ch <- 0
            wg.Done()
        }()
        wg.Wait()
    
    }
    

Restricting Data Flow

  • by default channels are bidirectional
  • channel can be cast to send only or receive only versions
  • send only: chan <- int
  • receive only: <-chan int
    package main
    
    import (
        "fmt"
        "sync"
    )
    
    var wg = sync.WaitGroup{}
    
    func main() {
        ch := make(chan int)
        wg.Add(2)
        go func(ch <-chan int) {
            i := <-ch
            fmt.Println(i)
            wg.Done()
        }(ch)
        go func(ch chan<- int) {
            ch <- 0
            wg.Done()
        }(ch)
        wg.Wait()
    
    }
    

Buffered Channels

  • channels block
  • sender side until receiver is available
  • receiver side until message is available
  • buffered channels contain internal data stores
  • Use buffered channels when send and receive have asymmetric loading
package main

import (
    "fmt"
    "sync"
)

var wg = sync.WaitGroup{}

func main() {
    ch := make(chan int, 2)
    wg.Add(2)
    go func(ch <-chan int) {
        i := <-ch
        fmt.Println(i)
        j := <-ch
        fmt.Println(j)
        wg.Done()
    }(ch)
    go func(ch chan<- int) {
        ch <- 0
        ch <- 1
        wg.Done()
    }(ch)
    wg.Wait()

}

Range Loops and Closing Channels

  • use to monitor channel and process messages as they arrive
  • loop exits when channel is closed
    package main
    
    import (
        "fmt"
        "sync"
    )
    
    var wg = sync.WaitGroup{}
    
    func main() {
        ch := make(chan int, 2)
        wg.Add(2)
        go func(ch <-chan int) {
            for i := range ch {
                fmt.Println(i)
            }
            wg.Done()
        }(ch)
        go func(ch chan<- int) {
            ch <- 0
            ch <- 1
            close(ch)
            wg.Done()
        }(ch)
        wg.Wait()
    
    }
    
package main

import (
    "fmt"
    "sync"
)

var wg = sync.WaitGroup{}

func main() {
    ch := make(chan int, 2)
    wg.Add(2)
    go func(ch <-chan int) {
        for {
            if i, ok := <-ch; ok {
                fmt.Println(i)
            } else {
                break
            }
        }       
        wg.Done()
    }(ch)
    go func(ch chan<- int) {
        ch <- 0
        ch <- 1
        close(ch)
        wg.Done()
    }(ch)
    wg.Wait()

}

Select Statements

  • allows goroutine to monitor several channels at once
  • block if all channels block
  • if multiple channels receive value simultaneously, behavior is undefined
  • no blocking select statement can involve a dealt case
    package main
    
    import (
        "fmt"
        "time"
    )
    
    const (
        logInfo    = "INFO"
        logWarning = "WARNING"
        logError   = "ERROR"
    )
    
    type LogEntry struct {
        time     time.Time
        severity string
        message  string
    }
    
    var logCh = make(chan LogEntry, 50)
    var doneCh = make(chan struct{})
    
    func main() {
        go logger()
        logCh <- LogEntry{time.Now(), logInfo, "App is startting"}
        logCh <- LogEntry{time.Now(), logInfo, "App is shutting down"}
        time.Sleep(100 * time.Millisecond)
        doneCh <- struct{}{}
    }
    
    func logger() {
        for {
            select {
            case entry := <-logCh:
                fmt.Printf("%v - [%v]%v\n", entry.time.Format("2006-01-02"), entry.severity, entry.message)
            case <-doneCh:
                break
            }
        }
    }