Middle
What rules should be considered when declaring a variable in a goroutine?
sobes.tech AI
Answer from AI
// Rule 1: Avoid sharing variables without synchronization.
// Goroutines run in parallel, and access to the same variable
// without locks or atomic operations can lead to race conditions.
// Use sync.Mutex or channels for safe access.
// Example with race condition:
var counter int
func incrementBad() {
counter++ // Might be unsafe for concurrent access
}
// Example with Mutex:
import "sync"
var (
counterSafe int
mutex sync.Mutex
)
func incrementSafe() {
mutex.Lock()
defer mutex.Unlock()
counterSafe++
}
// Rule 2: Prefer passing data between goroutines via channels.
// Go idiom: "Do not share memory by communicating, but communicate by sharing memory".
// Channels provide synchronization and order access to data.
// Example with channel:
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
// Process task
results <- j * 2 // Send result
}
}
// Rule 3: Be cautious with closures capturing variables from outer scope.
// A goroutine may start executing after the loop or function in which it was created has finished.
// If the closure captures a variable by reference (default behavior),
// it may get an unexpected value. Copy the variable if needed inside the goroutine.
// Example with unexpected closure behavior:
func badGoroutineLoop() {
for i := 0; i < 5; i++ {
go func() {
// By the time all goroutines start, i is most likely 5
// fmt.Println(i) // Output: 5 5 5 5 5
}()
}
}
// Example with correct variable capture:
func goodGoroutineLoop() {
for i := 0; i < 5; i++ {
iLocal := i // Create a local copy of the variable
go func() {
// fmt.Println(iLocal) // Output: 0 1 2 3 4 (order may vary)
}()
}
}
// Rule 4: Use sync.WaitGroup to wait for all goroutines to finish.
// This prevents premature termination of the main goroutine, e.g., main(),
// before parallel tasks are completed.
// Example with WaitGroup:
import "sync"
var wg sync.WaitGroup
func main() {
for i := 0; i < 3; i++ {
wg.Add(1) // Increment wait counter
go func(id int) {
defer wg.Done() // Signal completion
// Work...
}(i)
}
wg.Wait() // Wait until counter is zero
// All goroutines are finished
}