time & sync extras
The time package
time.Time and time.Now
time.Time represents a moment in time. time.Now() returns the current local time:
Measuring elapsed time
time.Since(t) returns how much time has passed since t โ the idiomatic way to time an operation:
time.Duration
A time.Duration is just int64 nanoseconds. Use the named constants to avoid magic numbers:
time.Sleep and time.After
time.Sleep blocks the current goroutine. time.After returns a channel that receives after the duration โ useful in select:
time.Ticker
A Ticker fires on a regular interval. Always call ticker.Stop() when done โ a forgotten ticker leaks a goroutine:
sync.Once โ exactly-once initialisation
sync.Once runs a function exactly once, no matter how many goroutines call it concurrently. The classic use case is lazy singleton initialisation:
After the first call completes, once.Do becomes a no-op for every subsequent call โ even from other goroutines. No mutex needed in the caller.
sync.RWMutex โ shared reads, exclusive writes
A sync.RWMutex allows multiple concurrent readers but only one writer at a time. Use it when reads are frequent and writes are rare:
| Method | Behaviour |
|---|---|
mu.Lock() | Exclusive write lock โ blocks until all readers/writers release |
mu.Unlock() | Release write lock |
mu.RLock() | Shared read lock โ multiple goroutines can hold simultaneously |
mu.RUnlock() | Release read lock |
Rule of thumb: if reads outnumber writes significantly (e.g., a cache), sync.RWMutex gives better throughput than a plain sync.Mutex. For balanced read/write access, the overhead of tracking read locks may not be worth it.
Knowledge Check
What is the idiomatic Go way to measure how long a function call takes?
Why must you call ticker.Stop() when done with a time.Ticker?
How does sync.RWMutex differ from sync.Mutex?