MVar
- can be empty
- used to implement synchronization patterns between threads
- allows one-way communication between threads
- can be faster than
TVar
in some cases
TVar
- can not be empty
- atomic transactions
- “shared memory” between threads; can be used to implement, for example, a lookup cache from which multiple threads can read/write
- access is linear time in the number of operations in the transaction log
- long running transactions are vulnerable to starvation if there are many shorter transactions, preventing them from commiting successfully
IORef
- mutable pointer-like reference
- often used for destructive
IO
writes/updates - has atomic CAS operations, but complex transactional logic is better suited to a
TVar
There is not really a hard and fast rule for when to use MVar
or TVar
.
If the resource I’m guarding will ever be “missing” (as opposed to empty, consider Nothing
vs Just mempty
), then MVar
often makes the most sense. If I will need to perform atomic blocks of modifications to the resource, then TVar
is most suitable.