Channels

Channels are a queue of values of a specific type which can be used to share information safely between goroutines. You can read more about the uses of channels with goroutines in the Pipelines article on the go blog. Before using channels, consider other options, particularly if you just need to control access to shared state. You can use mutexes to control access to state across goroutines, which is much simpler than channels. Use channels to orchestrate more complex behaviour like signalling between goroutines, passing ownership of data, or distributing units of work.

Nil Channels

Sending to a nil channel blocks forever:

func main() {
    var c chan string
    // send to nil channel blocks forever
    c <- "test" 
}

Receive on a nil channel blocks forever:

func main() {
    var c chan string
    // receive on nil blocks forever
    fmt.Println(<-c) 
}

Closed Channels

Sending to a closed channel causes a panic

package main

import (
    "fmt"
)

func main() {
    output := make(chan int, 1)
    write(output, 2) // send 
    close(output)    // close 
    write(output, 3) // send after close = panic
}

A receive from a closed channel returns the zero value immediately

package main

import "fmt"

func main() {
    c := make(chan int, 2)
    c <- 1
    c <- 2
            c <- 3
    close(c)
    for i := 0; i < 5; i++ {
       fmt.Printf("%d ", <-c) 
    }
}

outputs the channel values then the zero value

1 2 0 0 0

Instead you can use a range loop to just get the values

func main() {
    c := make(chan int, 2)
    c <- 1
    c <- 2
    close(c)
    for v := range c {
        fmt.Printf("%d ", v)
    }
}

Stopping a goroutine

You can use a channel to stop a goroutine by using the channel to signal completion.

// create a signal channel 
done := make(chan bool)

// launch the goroutine 
go func() {

    // listen for signals
    for {
        select {
        case <- done:
            return
        default:
            // Do something
            // ...
        }
    }
}()

// Do something
// ... 

// Stop the goroutine
done <- true

Deadlocks

Go channels created with make(chan T) without a size are not buffered. An unbuffered channel is synchronous, you can only send when there is a receiver. If the reads don't match the writes, the anon goroutines deadlock.

func main() {
    channel := make(chan string)
    done_channel := make(chan bool)
    go func() {
        channel <- "value" // write 1
        channel <- "value" // write 2
        done_channel <- true
    }()
    variable := <-channel // read 1    
    ok := <-done_channel
    fmt.Println(variable,ok)
}

fatal error: all goroutines are asleep - deadlock!

func main() {
    channel := make(chan string)
    done_channel := make(chan bool)
    go func() {
        channel <- "write1" // write 1
        channel <- "write2" // write 2
        done_channel <- true
    }()
    variable := <-channel // read 1
    variable = <-channel  // read 2 required to finish
    ok := <-done_channel
    fmt.Println(variable, ok)
}

write2 true

Counting channel elements

If you want to know how many elements are in a channel, you can just use len(channel)

func main() {
        c := make(chan int, 100)
        for i := 0; i < 34; i++ {
                c <- 0
        }
        fmt.Println(len(c))
}

results matching ""

    No results matching ""