Channel definition

A channel is a conduit for communication between Go coroutines. By using channels, data can be sent from one end and received from the other.

var name chan T
Copy the code

Declare a new channel with the name keyword and specify the data type T that the channel transmits.

To create a channel, we need to initialize it with the make function.

ch := make(chan T,size)
Copy the code

When creating a channel, you need to specify the data type T for the channel. If size is specified, that is, the length of the channel is specified.

Channel Sends and receives data

A channel is a queue that ensures that data is first in, first out, and that only one Goroutine accesses the channel at a time to send and fetch data.

Send data format:

Ch < -val // sends val to channel CHCopy the code

Sending data to a channel after the channel is filled blocks the current Goroutine.

Received data format:

Val := < -ch // reads a value from channel CH and assigns it to valCopy the code

A small example of channels used for coroutines:

package main

import (  
    "fmt"
)

func hello(done chan bool) {  
    fmt.Println("goroutine 1")
    done <- true
}
func main() {  
    done := make(chan bool)
    go hello(done)
    <-done
    fmt.Println("main function")
}
Copy the code

Creates a bool channel done and passes done as an argument to the Hello coroutine. We receive data over the channel done. At this point, the code blocks, and the program won’t skip to the next line unless a coroutine writes to done. The output is as follows:

goroutine 1  
main function
Copy the code

If there is no data in the channel CH, it will block reading into the Goroutine until data is put into the channel.

val,ok := <- ch
Copy the code

Check that OK is true to determine whether valid data has been read. The value read from a closed channel will be zero for that channel type. For example, when the channel is an int channel, the value read from the closed channel will be 0.

package main

import (
	"fmt"
)

func producer(chnl chan int) {
	for i := 0; i < 10; i++ {
		chnl <- i
	}
	close(chnl)
}
func main() {
	ch := make(chan int)
	go producer(ch)
	for {
		v, ok := <-ch
		if ok == false {
			break
		}
		fmt.Println("Received ", v, ok)
	}
}
Copy the code

The output is as follows:

Received 0 true Received 1 true Received 2 true Received 3 true Received 4 true Received 5 true Received 6 true Received  7 true Received 8 true Received 9 trueCopy the code

A deadlock

One important consideration when using channels is deadlocks. When a Go coroutine sends data to a channel, it is expected that other Go coroutines will receive the data. If not, the program will trigger panic at runtime, creating a deadlock.

Similarly, when a Go coroutine is waiting to receive data from a channel, we expect other Go coroutines to write to that channel, or else the program will trigger panic.

package main

func main() {  
    ch := make(chan int)
    ch <- 2
}
Copy the code

The output is as follows:

fatal error: all goroutines are asleep - deadlock!
Copy the code

The channel CH created in the program sends 2 to the channel through CH <-2, but no other coroutines receive data from CH, so the program triggers panic.

A one-way channel

A channel that can only send or receive data is called a one-way channel.

Just write the definition:

type Sender chan<- T
Copy the code

Read-only channel definition:

type Reciver <-chan T
Copy the code

T is the data type of the channel. If you receive data into a read-only channel, the compiler will report an error. Similarly, an error is reported when reading data from a single channel.

package main

import "fmt"

func sendData(sendch chan<- int) {  
    sendch <- 10
}

func main() {  
    sendch := make(chan<- int)
    go sendData(sendch)
    fmt.Println(<-sendch)
}
Copy the code

The output is as follows:

invalid operation: <-sendch (receive from send-only type chan<- int)
Copy the code

The compiler reported an error when sendch attempted to receive data over the send-only channel. Here’s an example of correct use:

package main import "fmt" func main() { c := make(chan int) var readc <- chan int = c var writec chan <- int = c go SetChan(writec) GetChan(readc) } func SetChan(writec chan <- int) { for i:=0; i<5; i++ { writec <- i } } func GetChan(readc <- chan int) { for i:=0; i<5; I++ {ftt. Printf(" I am GetChan, SetChan return message is %d\n",< -readc)}}Copy the code

The output is as follows:

I'm GetChan, I'm GetChan, I'm GetChan, I'm GetChan, I'm GetChan, I'm GetChan, I'm GetChan, I'm GetChan, So SetChan returns 3 and I'm GetChan, SetChan returns 4Copy the code

Channel with buffer

The sending and receiving processes of the unbuffered channel are blocked. If the length of a channel is specified when creating data, the channel will have a buffer. Sending data to a Buffered Channel is blocked only if the buffer is full. Similarly, receiving data from the buffered channel is blocked only if the buffer is empty. Such as:

package main

import (
	"fmt"
)


func main() {
	ch := make(chan int, 2)
	ch <- 0
	ch <- 2
	fmt.Println(<- ch)
	fmt.Println(<- ch)
}
Copy the code

The output is as follows:

0
2
Copy the code

You can see that the above program did not report an error, and the program did not block.

Here is an example to understand when blocking occurs when writing data to a buffered channel.

package main

import (  
    "fmt"
    "time"
)

func write(ch chan int) {  
    for i := 0; i < 5; i++ {
        ch <- i
        fmt.Println("successfully wrote", i, "to ch")
    }
    close(ch)
}
func main() {  
    ch := make(chan int, 2)
    go write(ch)
    time.Sleep(2 * time.Second)
    for v := range ch {
        fmt.Println("read value", v,"from ch")
        time.Sleep(1 * time.Second)

    }
}
Copy the code

The write coroutine immediately writes 0 and 1 to ch, then blocks until the value in CH is read. Therefore, the program immediately prints out the following two lines:

successfully wrote 0 to ch  
successfully wrote 1 to ch
Copy the code

After printing the above two lines, writing to CH in the write coroutine blocks until a value of ch is read. The Go main coroutine sleeps for two seconds before reading the channel, so the program will not print any results during the sleep. After the main coroutine finishes hibernation, it starts to read channel CH using the for range loop, prints out the read value and then sleeps for two seconds. This cycle does not end until CH is closed. So the program prints the following two lines after two seconds:

read value 0 from ch  
successfully wrote 2 to ch
Copy the code

This process continues until the channel reads all the values and closes the channel in the WRITE coroutine. The final output is as follows:

successfully wrote 0 to ch  
successfully wrote 1 to ch  
read value 0 from ch  
successfully wrote 2 to ch  
read value 1 from ch  
successfully wrote 3 to ch  
read value 2 from ch  
successfully wrote 4 to ch  
read value 3 from ch  
read value 4 from ch
Copy the code

What is SELECT?

The SELECT statement is used to select between multiple send/receive channel operations. The SELECT statement blocks until the send/receive operation is ready. If more than one channel operation is ready, select randomly selects one of them for execution. This syntax is similar to switch, except that each case statement is a channel operation.

package main import "fmt" func main() { ch1 := make(chan int, 1) ch2 := make(chan int, 1) ch3 := make(chan int, 1) ch1 <- 1 ch2 <- 1 ch3 <- 1 select { case <- ch1: fmt.Println("ch1") case <- ch2: fmt.Println("ch2") case <- ch3: Println("ch3") default: Println("ch3")}}Copy the code

The output is as follows:

ch1
Copy the code

Reference links: studygolang.com/articles/12…