Skip to content

Instantly share code, notes, and snippets.

@qnikst
Created May 17, 2017 06:25
Show Gist options
  • Save qnikst/734094449c8f13ffd7979391c24b8f34 to your computer and use it in GitHub Desktop.
Save qnikst/734094449c8f13ffd7979391c24b8f34 to your computer and use it in GitHub Desktop.
Simple storage that you can use to control concurrent evaluations.
import Control.Concurrent.Async
import Control.Concurrent.STM
import Control.Exception
import Control.Monad
import qualified Data.Map as Map
import Data.Map (Map)
import System.IO.Unsafe
-- | Version1 - starts async only when it's evaluated
-- Composable
--
createOrLoad :: Ord k => TVar (Map k (Async ())) -> k -> STM (Async ())
createOrLoad t k = do
c <- readTVar t
case Map.lookup k c of
Nothing -> do writeTVar t (Map.insert k a c)
return a
Just x -> return x
where
a = unsafePerformIO $ async $ return ()
-- | Do not use unsafe stuff, async is created immediately
-- Non composable (Uses IO).
-- Readers rerun transaction on each change (stm-containers is a solution).
-- Exception safe
createOrLoad2 :: Ord k => TVar (Map k (Either () (Async ()))) -> k -> IO (Async ())
createOrLoad2 t k = join internal where
internal = atomically $ do
c <- readTVar t
case Map.lookup k c of
Nothing -> do
modifyTVar' t (Map.insert k (Left ()))
return $ mask_ $ do
a <- async $ return ()
atomically $ modifyTVar' t (Map.insert k (Right a))
return a
Just (Left _) -> retry
Just (Right x) -> return $ return x
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment