I've been trying to get a understanding of concurrency, and I've been trying to work out what's better, one big IORef
lock or many TVar
s. I've came to the following guidelines, comments will be appreciated, regarding whether these are roughly right or whether I've missed the point.
Lets assume our concurrent data structure is a map m
, accessed like m[i]
. Lets also say we have two functions, f_easy
and f_hard
. The f_easy
is quick, f_hard
takes a long time. We'll assume the arguments to f_easy/f_hard
are elements of m
.
(1) If your transactions look roughly like this m[f_easy(...)] = f_hard(...)
, use an IORef
with atomicModifyIORef
. Laziness will ensure that m
is only locked for a short time as it's updated with a thunk. Calculating the index effectively locks the structure (as something is going to get updated, but we don't know what yet), but once it's known what that element is, the thunk over the entire structure moves to a thunk only over that particular element, and then only that particular element is "locked".
(2) If your transactions look roughly like this m[f_hard(...)] = f_easy(...)
, and the don't conflict too much, use lots of TVar
s. Using an IORef
in this case will effectively make the app single threaded, as you can't calculate two indexes at the same time (as there will be an unresolved thunk over the entire structure). TVar
s let you work out two indexes at the same time, however, the negative is that if two concurrent transactions both access the same element, and one of them is a write, one transaction must be scrapped, which wastes time (which could have been used elsewhere). If this happens a lot, you may be better with locks that come (via blackholing) from IORef
, but if it doesn't happen very much, you'll get better parallelism with TVar
s.
Basically in case (2), with IORef
you may get 100% efficiency (no wasted work) but only use 1.1 threads, but with TVar
if you have a low number of conflicts you might get 80% efficiency but use 10 threads, so you still end up 7 times faster even with the wasted work.
MVar
is entirely absent. – Tyrothricin