What is the difference between an IORef and an MVar?
Asked Answered
T

1

19

I'm having a little trouble understanding the basic difference between the IORef type and the MVar type in Haskell. Can someone help me out with this? They appear to solve the same problem. MVar seems to be targeted at multithreading, but IORef has the atomicModifyIORef function.

Thanks!

Turnbow answered 7/3, 2011 at 6:49 Comment(1)
MVars represent a queue-like abstraction which can take at most one element with blocking semantics, whereas an IORef has always one element in it.Charcuterie
E
22

MVar is, like you said, targeted at multithreading while IORef can be used both as mutable variable in a single threaded program or as a synchronization construct in a multithreaded program.

IORef can be used together with atomicModifyIORef to get compare-and-swap (CAS) behavior: writers and readers can synchronize on a single pure value, stored in the IORef. Readers use readIORef to read a value and writers use atomicModifyIORef to write a value. Note that atomicModifyIORef doesn't let writers perform any side effects inside the critical section (i.e. they can only use a pure function when atomically changing the value).

MVar allows you to implement arbitrary critical sections (using withMVar), that may contain side effects. They can also be used just like an IORef (as described in the previous paragraph), but at a higher cost.

If you want an intuition for what kind of semantic IORef implements its the same as the CAS semantics Rich Hickey describes in a talk on Clojure's concurrency model: http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey

Edit: In addition, you cannot run into deadlocks using IORef (but there still might be contention, causing retries).

Ethiopian answered 7/3, 2011 at 8:4 Comment(3)
I implemented database connection pool for use in web app. It requires only CAS actions and there's only one object it works with: the list of connections. I am using MVar to hold a Pool. Would you recommend to change it to IORef ? You are saying MVar incurs "a higher cost". Are there any benchmarks ?Foolscap
I would use an IORef. This is what we use in the GHC I/O manager to store an IntMap that maps file descriptors to callbacks. Remember that IORefs (and MVars) are lazy so you'd have to do something like: do !_ <- atomicModifyIORef ref (\ m -> let m' = insert k v m in (m', m') if you want the result to be evaluated in the writer instead of the reader. I don't have any benchmarks handy.Ethiopian
@Ethiopian is there any thumb-rule for when one should use an IORef and when one should use an MVar?Medrek

© 2022 - 2024 — McMap. All rights reserved.