Acceso a datos concurrentes con Mutexes

GolangGolangBeginner
Practicar Ahora

This tutorial is from open-source community. Access the source code

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

Este laboratorio tiene como objetivo demostrar cómo utilizar mutexes para acceder de manera segura a datos a través de múltiples goroutines.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL go(("Golang")) -.-> go/ConcurrencyGroup(["Concurrency"]) go/ConcurrencyGroup -.-> go/mutexes("Mutexes") subgraph Lab Skills go/mutexes -.-> lab-15490{{"Acceso a datos concurrentes con Mutexes"}} end

Mutexes

El problema que se debe resolver en este laboratorio es incrementar un contador nombrado en un bucle utilizando múltiples goroutines y asegurarse de que el acceso al contador esté sincronizado.

  • Utilice una estructura Container para almacenar un mapa de contadores.
  • Utilice un Mutex para sincronizar el acceso al mapa counters.
  • La estructura Container debe tener un método inc que tome una cadena name e incremente el contador correspondiente en el mapa counters.
  • El método inc debe bloquear el mutex antes de acceder al mapa counters y desbloquearlo al final de la función utilizando una declaración defer.
  • Utilice la estructura sync.WaitGroup para esperar a que las goroutines terminen.
  • Utilice la función fmt.Println para imprimir el mapa counters.
## Ejecutar el programa muestra que los contadores
## se actualizan como se esperaba.

## A continuación, veremos cómo implementar esta misma tarea
## de administración de estado utilizando solo goroutines y canales.

A continuación se muestra el código completo:

// En el ejemplo anterior vimos cómo administrar un estado
// de contador simple utilizando [operaciones atómicas](atomic-counters).
// Para un estado más complejo, podemos utilizar un [_mutex_](https://en.wikipedia.org/wiki/Mutual_exclusion)
// para acceder de manera segura a datos a través de múltiples goroutines.

package main

import (
	"fmt"
	"sync"
)

// Container almacena un mapa de contadores; dado que queremos
// actualizarlo concurrentemente desde múltiples goroutines,
// agregamos un `Mutex` para sincronizar el acceso.
// Tenga en cuenta que los mutexes no deben ser copiados,
// por lo que si esta `struct` se pasa por ahí, debe hacerse
// por puntero.
type Container struct {
	mu       sync.Mutex
	counters map[string]int
}

func (c *Container) inc(name string) {
	// Bloque el mutex antes de acceder a `counters`; desbloque
	// it al final de la función utilizando una declaración [defer](defer).
	c.mu.Lock()
	defer c.mu.Unlock()
	c.counters[name]++
}

func main() {
	c := Container{
		// Tenga en cuenta que el valor cero de un mutex es usable tal cual,
		// por lo que no es necesario inicializarlo aquí.
		counters: map[string]int{"a": 0, "b": 0},
	}

	var wg sync.WaitGroup

	// Esta función incrementa un contador nombrado
	// en un bucle.
	doIncrement := func(name string, n int) {
		for i := 0; i < n; i++ {
			c.inc(name)
		}
		wg.Done()
	}

	// Ejecute varias goroutines concurrentemente; tenga en cuenta
	// que todas acceden al mismo `Container`,
	// y dos de ellas acceden al mismo contador.
	wg.Add(3)
	go doIncrement("a", 10000)
	go doIncrement("a", 10000)
	go doIncrement("b", 10000)

	// Espere a que las goroutines terminen
	wg.Wait()
	fmt.Println(c.counters)
}

Resumen

En este laboratorio, aprendimos cómo utilizar mutexes para acceder de manera segura a datos a través de múltiples goroutines. Creamos una estructura Container para almacenar un mapa de contadores y utilizamos un Mutex para sincronizar el acceso al mapa counters. También implementamos un método inc para incrementar el contador nombrado y utilizamos la estructura sync.WaitGroup para esperar a que las goroutines terminen. Finalmente, imprimimos el mapa counters utilizando la función fmt.Println.