sync.RWMutex
In a fit of anxiety after seeing his $100 deposit vanish without a trace,
Bob writes a program to check his bank balance
hundreds of times a second. He runs it at home, at work, and on his
phone. The bank notices that the increased traffic is delaying deposits
and withdrawals, because all the Balance
requests run sequentially,
holding the lock exclusively and temporarily preventing other goroutines from
running.
Since the Balance
function only needs to read the state of the
variable, it would in fact be safe for multiple Balance
calls to run
concurrently, so long as no Deposit
or Withdraw
call is running.
In this
scenario we need a special kind of lock that allows read-only
operations to proceed in parallel with each other, but write
operations to have fully exclusive access. This lock is called a
multiple readers, single writer lock, and in Go it’s
provided by sync.RWMutex
:
var mu sync.RWMutex var balance int func Balance() int { mu.RLock() // readers lock defer mu.RUnlock() return balance }
The Balance
function now calls the RLock
and
RUnlock
methods to acquire and release a readers or
shared lock.
The Deposit
function, which is unchanged, calls the
mu.Lock
and mu.Unlock
methods to acquire and release a
writer or exclusive lock.
After this change, most of Bob’s Balance
requests run in parallel with each other and finish more quickly. The
lock is available for more of the time, and Deposit
requests can proceed in a timely manner.
RLock
can be used only if there are no
writes to shared variables in the critical section.
In general, we should not assume that logically read-only
functions or methods don’t also update some variables.
For example, a method that appears to be a simple accessor might also
increment an internal usage counter, or update a cache so that repeat
calls are faster.
If in doubt, use an exclusive Lock
.
It’s only profitable to use an RWMutex
when most of the
goroutines that acquire the lock are readers, and the lock is under
contention, that is, goroutines routinely have to wait to
acquire it.
An RWMutex
requires more complex internal bookkeeping, making
it slower than a regular mutex for uncontended locks.
44.200.26.112