When sharing data across goroutines, always use proper synchronization mechanisms to prevent race conditions. Race conditions are difficult to debug and can cause intermittent failures that only appear under load.
When sharing data across goroutines, always use proper synchronization mechanisms to prevent race conditions. Race conditions are difficult to debug and can cause intermittent failures that only appear under load.
Key practices:
func() {
mu.Lock()
defer mu.Unlock()
// Code that might panic or return early
}()
// When parallelism > 1, clone to prevent concurrent modifications
if parallelism > 1 {
resp = resp.CloneVT()
}
var rowAdded atomic.Bool
// Later in code executed by multiple goroutines
if len(rresult.Rows) > 0 {
rowAdded.Store(true)
}
// Check safely
if rowAdded.Load() {
// ...
}
func (ml *MemoryLogger) LogEvents() []*logutilpb.Event {
ml.mu.Lock()
defer ml.mu.Unlock()
return slices.Clone(ml.Events)
}
ctx, cancel := context.WithCancel(ctx)
defer cancel() // Prevents context leaks
// For high-throughput messaging where backpressure is a concern
mq := concurrency.NewMessageQueue[*TabletHealth]()
go func() {
for {
th, validRes := mq.Receive()
if validRes {
c <- th
}
}
}()
chan struct{}
over chan bool
for signaling:
// More efficient and idiomatic for simple signaling
semAcquiredChan := make(chan struct{})
// When signaling
semAcquiredChan <- struct{}{}
Run tests with the -race
flag to catch race conditions during development.
Enter the URL of a public GitHub repository