Welcome To Golang By Example

All operations/function on a channel in Go (Golang)

Overview

Below operations/functions are applicable for channel in golang

Let’s look at each operation/functions on a channel one by one

Send Operation

The send operation used to send data to the channel. Below is the format for sending to a channel

ch <- data

where

Note that type of data and type of channel should match.
Send operation can block for a buffered or unbuffered channel in the following way

 Let's look at the program for send operation after we have understood the receive operation as well

Receive Operation

The receive operation used to read data from the channel Below is the format for receiving from a channel

data := <- ch 

where

Let's see an example of where we will send data from one goroutine and receive that data in another goroutine.

package main

import (
    "fmt"
    "time"
)

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

    fmt.Println("Sending value to channnel")
    go send(ch)

    fmt.Println("Receiving from channnel")
    go receive(ch)

    time.Sleep(time.Second * 1)
}

func send(ch chan int) {
    ch <- 1
}

func receive(ch chan int) {
    val := <-ch
    fmt.Printf("Value Received=%d in receive function\n", val)
}

Output

Sending value to channel
Receiving from channel
Value Received=1 in receive function

In the above program, we created a channel that can only transport data of type int. Function send() and receive() are started as a goroutine. We are sending data to the channel in send() goroutine and receiving data in the receive() goroutine.

Receive operation can block for a buffered or unbuffered channel in the following way

Close operation on a channel

Close is an inbuilt function that can be used to close a channel. Closing of a channel means that no more data can we send to the channel.  Channel is generally closed when all the data has been sent and there's no more data to be send. Let's see a program

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    go sum(ch, 3)
    ch <- 2
    ch <- 2
    ch <- 2
    close(ch)
    time.Sleep(time.Second * 1)
}

func sum(ch chan int, len int) {
    sum := 0
    for i := 0; i < len; i++ {
        sum += <-ch
    }
    fmt.Printf("Sum: %d\n", sum)
}

Output

Sum: 6

In the above program, we created a channel.  Then we called the sum function in a goroutine. In the main function, we send 3 values to the channel and after that, we closed the channel indicating that no more values can be sent to the channel. The sum function iterates over the channel using the for loop and calculates the sum value.

Sending on a close channel will cause a panic.  See the program below

package main

func main() {
    ch := make(chan int)
    close(ch)
    ch <- 2
}

Output

panic: send on closed channel

Also closing a already closed channel will cause a panic

While receiving from a  channel we can also use an additional variable  to determine if the channel  has been closed.  Below is the syntax for the same

val,ok <- ch

The value of ok will be

package main
import (
    "fmt"
)
func main() {
    ch := make(chan int, 1)
    ch <- 2
    val, ok := <-ch
    fmt.Printf("Val: %d OK: %t\n", val, ok)

    close(ch)
    val, ok = <-ch
    fmt.Printf("Val: %d OK: %t\n", val, ok)
}

Output

Val: 2 OK: true
Val: 0 OK: false

In the above program created a channel of capacity one.  Then we send one value to the channel.  The ok variable in the first receive is true since the channel is not closed. The ok variable in the second  receive is  false because the channel is closed

Length of a channel using len() function

Builtin len() function can be used to get the length of a channel. The length of a channel is the number of elements that are already there in the channel. So length actually represents the number of elements queued in the buffer of the channel. Length of a channel is always less than or equal to the capacity of the channel.

Length of unbuffered channel is always zero

package main

import "fmt"

func main() {
	ch := make(chan int, 3)
	ch <- 5
	fmt.Printf("Len: %d\n", len(ch))

	ch <- 6
	fmt.Printf("Len: %d\n", len(ch))
	ch <- 7
	fmt.Printf("Len: %d\n", len(ch))
}

Output

Len: 1
Len: 2
Len: 3

In the above code, the first created a channel of capacity 3.  After that, we keep sending some value to the channel. As you can notice from your output that after each send operation to the length of channel increases by one as the length denotes the number of item in the buffer of channel.

Capacity of a channel using cap() function

The capacity of a buffered channel is the number of elements that channel can hold. Capacity refers to the size of the buffer of the channel. The capacity of the channel can be specified during the creation of the channel while using the make function. The second argument is the capacity

The capacity of an unbuffered channel is always zero

package main

import "fmt"

func main() {
    ch := make(chan int, 3)
    fmt.Printf("Capacity: %d\n", cap(ch))
}

Output

Capacity: 3

In the above program we specified the capacity as 3 in the make function

make(chan int, 3)

Let's see summary table which shows the result of each operation on the different types of channel

CommandUnbuffered Channel(Not Closed and not nil)Buffered Channel(Not Closed and not nil)Closed ChannelNil Channel
SendBlock if there is is no corresponding receiver otherwise successBlock if the channel is full otherwise successPanicBlock forever
ReceiveBlock if there is no corresponding sender otherwise successBlock if the channel is empty otherwise successReceives the default value of data type from the channel if channel is empty else  receives the actual valueBlock forever
CloseSuccessSuccessPanicPanic
Length0Number of elements queued in the buffer of the channel-0 if unbuffered channel-Number of elements queued in the buffer if buffered channel0
Capacity0Size of the buffer of the channel-0 if unbuffered channel-Size of the buffer if buffered channel0