โฑ๏ธtime & sync extrasLESSON

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:

MethodBehaviour
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?