Go component learning - channel (concurrency)

Introduction:

Recently, while learning about the concurrency channel module of go language, I saw some examples in ardan labs to promote the understanding of some principles and uses of channel

1, Definition of channel

Channels allow goroutines to communicate with each other through the use of signaling semantics. Channels accomplish this signaling through the use of sending/receiving data or by identifying state changes on individual channels. Don't architect software with the idea of channels being a queue, focus on signaling and the semantics that simplify the orchestration required.

Channels allow goroutine s to communicate with each other by using signaling semantics. The channel completes the signaling by using send / receive data or identifying state changes on a single channel. Instead of building software with the idea that channels are queues, focus on simplifying the signaling and semantics of the required orchestration.

2, How to use channel

Define a chan in go to start the channel mode

for example

	ch := make(chan int, 1)
	ch <- 1
	fmt.Println(<-ch)

The above ch < - 1 is to send data to the channel, and = = < - CH = = is to send data.

This enables the channel pipeline to receive and send data.

3, Some scenarios of channel

buffered

Blocking scenario, concurrent scenario, multi data transmission and multi-user reception need to be stored and retrieved slowly from the channel. The time delay is high, but high-performance and efficient transmission is realized.

unbuffered (non blocking)

Non blocking scenario is also common. It realizes the rapid sending and receiving of data. It is often used for peer-to-peer single gorountine, one-to-one chat room? Low latency, but it requires the establishment of multiple gorountine, which consumes a lot of performance.

4, Some simple scenario applications of channel

1) The parent goroutine waits for the data of the child goroutine to be sent through the channel

// waitForResult: In this pattern, the parent goroutine waits for the child
// goroutine to finish some work to signal the result.
// Parent goroutine waits for signal result
func waitForResult() {
	ch := make(chan string)

	go func() {
		time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
		ch <- "data"
		fmt.Println("child : sent signal")
	}()

	d := <-ch
	fmt.Println("parent : recv'd signal :", d)

	time.Sleep(time.Second)
	fmt.Println("-------------------------------------------------")
}

2) The parent goroutine sends 100 signals, and the child goroutine a pool will wait for the signal to be received

// pooling: In this pattern, the parent goroutine signals 100 pieces of work
// to a pool of child goroutines waiting for work to perform.
//The parent goroutine sends 100 signals, and the child goroutine pool will wait and work
func pooling() {
	ch := make(chan string)
	//Set the maximum number of CPU s that can be executed, which refers to threads
	g := runtime.GOMAXPROCS(0)
	fmt.Println("====",g)
	for c := 0; c < g; c++ {
		go func(child int) {
			fmt.Println("!!!!!1")
			for d := range ch {
				fmt.Printf("child %d : recv'd signal : %s\n", child, d)
			}
			fmt.Printf("child %d : recv'd shutdown signal\n", child)
		}(c)
	}

	const work = 100
	for w := 0; w < work; w++ {
		ch <- "data" + strconv.Itoa(w)
		fmt.Println("parent : sent signal :", w)
	}

	close(ch)
	fmt.Println("parent : sent shutdown signal")

	time.Sleep(time.Second)
	fmt.Println("-------------------------------------------------")
}

3) Use the channel pipe to simulate a two person tennis match

// Sample program to show how to use an unbuffered channel to
// simulate a game of tennis between two goroutines.
//A simulated tennis match between two goroutines.
package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

func main() {

	// Create an unbuffered channel.
	court := make(chan int)

	// wg is used to manage concurrency.
	var wg sync.WaitGroup
	wg.Add(2)

	// Launch two players.
	go func() {
		player("Serena", court)
		wg.Done()
	}()

	go func() {
		player("Venus", court)
		wg.Done()
	}()

	// Start the set.
	court <- 1

	// Wait for the game to finish.
	wg.Wait()
}

// player simulates a person playing the game of tennis.
func player(name string, court chan int) {
	for {

		// Wait for the ball to be hit back to us.
		ball, wd := <-court
		if !wd {

			// If the channel was closed we won.
			fmt.Printf("Player %s Won\n", name)
			return
		}

		// Pick a random number and see if we miss the ball.
		n := rand.Intn(100)
		if n%13 == 0 {
			fmt.Printf("Player %s Missed\n", name)

			// Close the channel to signal we lost.
			close(court)
			return
		}

		// Display and then increment the hit count by one.
		fmt.Printf("Player %s Hit %d\n", name, ball)
		ball++

		// Hit the ball back to the opposing player.
		court <- ball
	}
}


5, Some prohibited items in channel

In the two methods of data sending and receiving, there are also some prohibitions after the channel pipe is closed

for instance

After the pipeline is closed, it is not allowed to send data. If the data is sent, a panic error will be generated.

	ch := make(chan int,2)
	ch <- 1 //Send 1 to pipeline ch
	fmt.Println(<-ch)//Receive data from pipeline 1
	close(ch)//Close the pipe
	ch <- 2 //The sending pipeline reports an error. The pipeline has been closed and cannot be sent again. panic
	fmt.Println(<-ch)

The above code will report panic: send on closed channel error

After testing, it is changed into the following code to confirm this prohibition

	ch := make(chan int,2)
	ch <- 1//Send 1 to pipeline ch
	ch <- 2//Send 2 to pipeline ch
	fmt.Println(<-ch)//Receive data from pipeline 1
	close(ch)
	fmt.Println(<-ch)//Receive data from pipeline 2

Article reference

  • ardan labs go training - github web adress "https://github.com/ardanlabs/gotraining"

Keywords: Go Back-end

Added by dabbott on Fri, 04 Feb 2022 05:02:08 +0200