Code with Go
About
  • Code With Go! 🚀
  • Hello World
  • Values
  • Variables
  • Constants
  • For Loop
  • If Else
  • Switch
  • Array
  • Slice
  • Map
  • Range
  • Functions
  • Multiple Return Values
  • Variadic Functions
  • Closure
  • Recursion
  • Pointers
  • Strings and Runes
  • Structs
  • Methods
  • Interfaces
  • Struct Embedding
  • Generics
  • Error
  • Goroutines
  • Channels
  • Channel Buffering
  • Channel Synchronization
  • Channel Directions
  • Select
  • Timeouts
  • Non-Blocking Channel Operations
  • Closing Channels
  • Range over Channels
  • Timers
  • Tickers
  • Worker Pools
  • Wait Groups
  • Rate Limiting
  • Atomic Counters
  • Mutexes
  • Stateful Goroutines
  • Sorting
  • Sorting by Functions
  • Panic
  • Defer
  • Recover
  • String Functions
  • String Formatting
  • Text Templates
  • Regular Expressions
  • JSON
  • XML
  • Time
  • Epoch
  • Time Formatting / Parsing
  • Random Numbers
  • Number Parsing
  • SHA256 Hashes
  • Base64 Encoding
  • Reading Files
  • Writing Files
  • Line Filters
  • File Paths
  • Directories
  • Temporary Files and Directories
  • Embed Directive
  • Testing and Benchmarking
  • Command-Line Arguments
  • Command-Line Flags
  • Command-Line Subcommands
  • Environment Variables
  • Logging
  • HTTP Client
  • HTTP Server
  • Context
  • Spawning Processes
  • Exec'ing Processes
  • Signals
  • Exit
  • Resize Image
Powered by GitBook
On this page

Was this helpful?

Edit on GitHub

Stateful Goroutines

This Go code demonstrates concurrent read and write operations on a state map using goroutines and channels. The program tracks the number of read and write operations using atomic operations. Let's break down the code with inline comments:

package main

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

// readOp represents a read operation.
type readOp struct {
	key  int
	resp chan int
}

// writeOp represents a write operation.
type writeOp struct {
	key  int
	val  int
	resp chan bool
}

func main() {
	// Variables to track the number of read and write operations using atomic counters.
	var readOps uint64
	var writeOps uint64

	// Channels for communication between goroutines.
	reads := make(chan readOp)
	writes := make(chan writeOp)

	// Goroutine simulating a stateful object with read and write operations.
	go func() {
		// Initial state map.
		var state = make(map[int]int)

		for {
			select {
			case read := <-reads:
				// Handling read operation: responding with the value from the state map.
				read.resp <- state[read.key]
			case write := <-writes:
				// Handling write operation: updating the state map with the provided key-value pair.
				state[write.key] = write.val
				write.resp <- true
			}
		}
	}()

	// Goroutines simulating concurrent read operations.
	for r := 0; r < 100; r++ {
		go func() {
			for {
				// Generating a random key for the read operation.
				read := readOp{
					key:  rand.Intn(5),
					resp: make(chan int),
				}
				reads <- read
				<-read.resp
				// Incrementing the readOps counter using atomic operation.
				atomic.AddUint64(&readOps, 1)
				time.Sleep(time.Millisecond)
			}
		}()
	}

	// Goroutines simulating concurrent write operations.
	for w := 0; w < 10; w++ {
		go func() {
			for {
				// Generating random key-value pair for the write operation.
				write := writeOp{
					key:  rand.Intn(5),
					val:  rand.Intn(100),
					resp: make(chan bool),
				}
				writes <- write
				<-write.resp
				// Incrementing the writeOps counter using atomic operation.
				atomic.AddUint64(&writeOps, 1)
				time.Sleep(time.Millisecond)
			}
		}()
	}

	// Allowing some time for goroutines to perform read and write operations.
	time.Sleep(time.Second)

	// Loading and printing the final values of readOps and writeOps counters.
	readOpsFinal := atomic.LoadUint64(&readOps)
	fmt.Println("readOps:", readOpsFinal)
	writeOpsFinal := atomic.LoadUint64(&writeOps)
	fmt.Println("writeOps:", writeOpsFinal)
}

Output

readOps: 6723
writeOps: 680

Explanation:

  1. readOp and writeOp structures represent read and write operations, respectively.

  2. The main goroutine initializes channels for read and write operations, and a goroutine simulating a stateful object.

  3. Concurrent goroutines are created to simulate both read and write operations. The read operations retrieve a value from the state, and the write operations update the state.

  4. The atomic package is used to perform atomic operations on counters (readOps and writeOps) to track the number of read and write operations.

  5. The program runs for some time (time.Sleep(time.Second)) to allow goroutines to perform operations.

  6. The final values of the readOps and writeOps counters are loaded atomically and printed.

The code showcases a scenario where multiple goroutines concurrently read and write to a shared state, and atomic operations are used to safely track the number of operations. The use of channels ensures proper synchronization between goroutines.

PreviousMutexesNextSorting

Last updated 1 year ago

Was this helpful?