Notas de estudio "Go language combat" - combate de código de canal almacenado en búfer

Capítulo 6 Concurrencia

6.5 canales

6.5.2 Canales almacenados en búfer

concepto

Un canal almacenado en búfer es un canal que puede almacenar uno o más valores antes de ser recibido. Este
tipo de canal no obliga a que tanto el envío como la recepción se realicen entre rutinas. Las condiciones bajo las cuales un canal puede bloquear acciones de envío y recepción también son diferentes. La acción de recibir solo se bloqueará si no hay valores para recibir en el canal. La acción de envío solo se bloqueará si el canal no tiene búferes disponibles para contener el valor que se envía . Esto lleva a una gran diferencia entre los canales con y sin búfer: los canales sin búfer garantizan que las rutinas de envío y recepción intercambiarán datos al mismo tiempo; los canales con búfer no tienen tal garantía .

Código de combate

Veamos un ejemplo que usa un canal almacenado en búfer que administra un conjunto de rutinas para recibir y completar el trabajo.
Los canales almacenados en búfer proporcionan una forma clara e intuitiva de hacer esto, el código es el siguiente

// This sample program demonstrates how to use a buffered
// channel to work on multiple tasks with a predefined number
// of goroutines.
package main

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

const (
	numberGoroutines = 4  // Number of goroutines to use.
	taskLoad         = 10 // Amount of work to process.
)

// wg is used to wait for the program to finish.
var wg sync.WaitGroup

// init is called to initialize the package by the
// Go runtime prior to any other code being executed.
func init() {
	// Seed the random number generator.
	rand.Seed(time.Now().Unix())
}

// main is the entry point for all Go programs.
func main() {
	// Create a buffered channel to manage the task load.
	tasks := make(chan string, taskLoad)

	// Launch goroutines to handle the work.
	wg.Add(numberGoroutines)
	for gr := 1; gr <= numberGoroutines; gr++ {
		go worker(tasks, gr)
	}

	// Add a bunch of work to get done.
	for post := 1; post <= taskLoad; post++ {
		tasks <- fmt.Sprintf("Task : %d", post)
	}

	// Close the channel so the goroutines will quit
	// when all the work is done.
	close(tasks)

	// Wait for all the work to get done.
	wg.Wait()
}

// worker is launched as a goroutine to process work from
// the buffered channel.
func worker(tasks chan string, worker int) {
	// Report that we just returned.
	defer wg.Done()

	for {
		// Wait for work to be assigned.
		task, ok := <-tasks
		if !ok {
			// This means the channel is empty and closed.
			fmt.Printf("Worker: %d : Shutting Down\n", worker)
			return
		}

		// Display we are starting the work.
		fmt.Printf("Worker: %d : Started %s\n", worker, task)

		// Randomly wait to simulate work time.
		sleep := rand.Int63n(100)
		time.Sleep(time.Duration(sleep) * time.Millisecond)

		// Display we finished the work.
		fmt.Printf("Worker: %d : Completed %s\n", worker, task)
	}
}

resultado de la operación

go run listing24.go 
Worker: 1 : Started Task : 1
Worker: 3 : Started Task : 3
Worker: 4 : Started Task : 4
Worker: 2 : Started Task : 2
Worker: 3 : Completed Task : 3
Worker: 3 : Started Task : 5
Worker: 4 : Completed Task : 4
Worker: 4 : Started Task : 6
Worker: 1 : Completed Task : 1
Worker: 1 : Started Task : 7
Worker: 3 : Completed Task : 5
Worker: 3 : Started Task : 8
Worker: 1 : Completed Task : 7
Worker: 1 : Started Task : 9
Worker: 2 : Completed Task : 2
Worker: 2 : Started Task : 10
Worker: 4 : Completed Task : 6
Worker: 4 : Shutting Down
Worker: 3 : Completed Task : 8
Worker: 3 : Shutting Down
Worker: 2 : Completed Task : 10
Worker: 2 : Shutting Down
Worker: 1 : Completed Task : 9
Worker: 1 : Shutting Down

Los comentarios chinos y las explicaciones de los códigos específicos son los siguientes

 

 

 

Supongo que te gusta

Origin blog.csdn.net/wangchao701123/article/details/123108122
Recomendado
Clasificación