by Timur Dautov

What are the Channels in Golang

Channels are a powerful feature of Go that enable communication between goroutines. They are used to send and receive data between goroutines and synchronize their execution.

Channels are a fundamental part of Go's concurrency model and are used extensively in Go programs to coordinate the execution of concurrent tasks.

Create a new Channel#

To create a new channel, you can use the make function with the chan keyword followed by the type of data that the channel will carry. For example:

ch := make(chan int)

In the above example, we create a new channel ch that can carry integers.

Channels can also carry other types of data, such as strings, structs, or custom types.

Sending and receiving data#

You can send data to a channel using the <- operator followed by the channel variable. For example:

ch <- 42

In the above example, we send the integer 42 to the channel ch.

You can receive data from a channel using the <- operator on the left side of the channel variable. For example:

value := <-ch

In the above example, we receive a value from the channel ch and assign it to the variable value.

Buffered Channels#

Channels can be buffered, which means they can hold a fixed number of values before blocking the sender. You can create a buffered channel by passing the buffer size as the second argument to the make function. For example:

ch := make(chan int, 3) // Buffered channel with a capacity of 3
ch <- 1
ch <- 2
ch <- 3

Close the channel#

You can close a channel using the close function. Closing a channel indicates that no more values will be sent on the channel. Receivers can check if a channel is closed by using the second return value of the receive operation. For example:

close(ch)

Range over Channel#

You can use the range keyword to iterate over the values sent on a channel. The range keyword will continue to iterate until the channel is closed. For example:

for value := range ch {
    fmt.Println(value)
}

Select Statements#

Select statements are used to wait on multiple channel operations simultaneously. A select statement blocks until one of its cases can proceed. For example:

select {
case msg1 := <-ch1:
    fmt.Println("Received", msg1)
case msg2 := <-ch2:
    fmt.Println("Received", msg2)
case ch3 <- 3:
    fmt.Println("Sent 3 to ch3")
default:
    fmt.Println("No communication")
}

In the above example, the select statement waits for one of the cases to proceed. If multiple cases are ready, one is chosen at random.

Blocking Operations#

Channels are blocking by default, which means that sending or receiving data on a channel will block until the other side is ready. This property makes channels an effective synchronization mechanism for goroutines.

Example#

In this example, three worker goroutines receive jobs from the jobs channel and process them. The main goroutine sends five jobs to the channel and then closes it.

package main

import (
    "fmt"
    "time"
)

func worker(id int, ch chan int) {
    for job := range ch {
        fmt.Printf("Worker %d received job %d\n", id, job)
        time.Sleep(time.Second)
    }
}

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

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

    for j := 1; j <= 5; j++ {
        jobs <- j
        fmt.Printf("Sent job %d\n", j)
    }
    close(jobs)

    time.Sleep(time.Second * 5)
}