directory

  • preface
  • The body of the
  • At the end

preface

We know that channels in Golang are written at one end and read at the other. Basically, one channel handles its own logic, independent of the other channels. So, can the channels in Golang be managed uniformly? Let’s take a look today.

The body of the

Now that we’ve set out to achieve unified management of multiple channels, in other words multiplexing, we need a direction. Let’s take a look at the current state of the channels. Each channel has its own processing coroutine.

Let’s look at this code:

package main

import (
	"fmt"
)

func main(a) {
	// Define a channel ch1
	ch1 := make(chan int)

	// Enable subcoroutine goroutine to write data
	go func(a) {
		for i := 0; i < 11; i++ {
			ch1 <- i
			fmt.Println("Subcoroutine CH1 writes data:", i)
		}
		close(ch1) // Close the channel} ()// Define a channel ch2
	ch2 := make(chan int)

	// Enable subcoroutine goroutine to write data
	go func(a) {
		for i := 0; i < 11; i++ {
			ch2 <- i
			fmt.Println("Subcoroutine CH2 writes data:", i)
		}
		close(ch2) // Close the channel} ()// The main coroutine reads ch1 data
	for {
		v, ok := <-ch1
		if! ok { fmt.Println("Finish reading", ok)
			break
		}
		fmt.Println("Ch1 data read by the main coroutine is:", v)
	}

	// The main coroutine reads ch2 data
	for {
		v, ok := <-ch2
		if! ok { fmt.Println("Finish reading", ok)
			break
		}
		fmt.Println("Ch2 data read by the main coroutine is:", v)
	}

	fmt.Println("End of main coroutine")}Copy the code

The result is as follows:

Subcoroutine CH1 writes data:0Ch1 data read by the main coroutine is:0Ch1 data read by the main coroutine is:1Subcoroutine CH1 writes data:1Subcoroutine CH1 writes data:2Ch1 data read by the main coroutine is:2Ch1 data read by the main coroutine is:3Subcoroutine CH1 writes data:3Subcoroutine CH1 writes data:4Ch1 data read by the main coroutine is:4Ch1 data read by the main coroutine is:5Subcoroutine CH1 writes data:5Subcoroutine CH1 writes data:6Ch1 data read by the main coroutine is:6Ch1 data read by the main coroutine is:7Subcoroutine CH1 writes data:7Subcoroutine CH1 writes data:8Ch1 data read by the main coroutine is:8Ch1 data read by the main coroutine is:9Subcoroutine CH1 writes data:9Subcoroutine CH1 writes data:10Ch1 data read by the main coroutine is:10Read the endfalseCh2 data read by the main coroutine is:0Subcoroutine CH2 writes data:0Subcoroutine CH2 writes data:1Ch2 data read by the main coroutine is:1Ch2 data read by the main coroutine is:2Subcoroutine CH2 writes data:2Subcoroutine CH2 writes data:3Ch2 data read by the main coroutine is:3Ch2 data read by the main coroutine is:4Subcoroutine CH2 writes data:4Subcoroutine CH2 writes data:5Ch2 data read by the main coroutine is:5Ch2 data read by the main coroutine is:6Subcoroutine CH2 writes data:6Subcoroutine CH2 writes data:7Ch2 data read by the main coroutine is:7Ch2 data read by the main coroutine is:8Subcoroutine CH2 writes data:8Subcoroutine CH2 writes data:9Ch2 data read by the main coroutine is:9Ch2 data read by the main coroutine is:10Subcoroutine CH2 writes data:10Read the endfalseThe main coroutine endsCopy the code

Through the above code, we also see that each channel has its own coroutine, which then communicates with the main coroutine. This is very tedious, and a lot of the code is repetitive. Is there a way to reuse channels?

The answer is yes.

What we want to achieve is to use a single coroutine to handle all of the channel traffic. This requires the select keyword. What does it do?

Next, let’s look at one side of the code.

Example code:

package main

import (
	"fmt"
	"time"
)

func main(a) {
	ch1 := make(chan int)
	ch2 := make(chan int)
	go func(a) {
		for {
			select {
			case c1 := <-ch1:
				fmt.Println("Succeeded in obtaining data for channel CH1:", c1)
			case c2 := <-ch2:
				fmt.Println("Succeeded in obtaining data for channel CH2:", c2)
			case <-time.After(time.Second * 2) :// Use time.after to set the timeout response.
				fmt.Println("Timeout!!!!!")}}} ()for i := 0; i < 10; i++ {
		ch1 <- i
		fmt.Println("Channel CH1 writes data:", i)
	}
	for i := 0; i < 10; i++ {
		ch2 <- i
		fmt.Println("Channel CH2 writes data:", i)
	}
	time.Sleep(20) // Wait for the execution of the select coroutine to finish
}
Copy the code

Code execution result:

Succeeded in obtaining data for channel CH1:0Channel CH1 writes data:0Channel CH1 writes data:1Succeeded in obtaining data for channel CH1:1Succeeded in obtaining data for channel CH1:2Channel CH1 writes data:2Channel CH1 writes data:3Succeeded in obtaining data for channel CH1:3Succeeded in obtaining data for channel CH1:4Channel CH1 writes data:4Channel CH1 writes data:5Succeeded in obtaining data for channel CH1:5Succeeded in obtaining data for channel CH1:6Channel CH1 writes data:6Channel CH1 writes data:7Succeeded in obtaining data for channel CH1:7Succeeded in obtaining data for channel CH1:8Channel CH1 writes data:8Channel CH1 writes data:9Succeeded in obtaining data for channel CH1:9Succeeded in obtaining data for channel CH2:0Channel CH2 writes data:0Channel CH2 writes data:1Succeeded in obtaining data for channel CH2:1Succeeded in obtaining data for channel CH2:2Channel CH2 writes data:2Channel CH2 writes data:3Succeeded in obtaining data for channel CH2:3Succeeded in obtaining data for channel CH2:4Channel CH2 writes data:4Channel CH2 writes data:5Succeeded in obtaining data for channel CH2:5Succeeded in obtaining data for channel CH2:6Channel CH2 writes data:6Channel CH2 writes data:7Succeeded in obtaining data for channel CH2:7Succeeded in obtaining data for channel CH2:8Channel CH2 writes data:8Channel CH2 writes data:9Succeeded in obtaining data for channel CH2:9
Copy the code

As you can see from the above code, we can process all channel messages with only one anonymous coroutine, realizing channel reuse. And the whole process is also very clear, very easy to manage.

At the end

In fact, the management of Golang channels is very complicated, and we need to focus on it in the future. Ok, that’s all for today’s introduction to the channel, thank you.