Tratando de entender cosas simples de Haskell STM
-
28-10-2019 - |
Pregunta
Me quedé atascado en comprender el concepto de Atómica en STM.
Ilustrato con un ejemplo
import Control.Concurrent
import Control.Concurrent.STM
import Control.Monad
import qualified Data.Map as Map
main :: IO ()
main = do
d <- atomically$ newTVar Map.empty
sockHandler d
sockHandler :: TVar (Map.Map String Int)-> IO ()
sockHandler d = do
forkIO $ commandProcessor d 1
forkIO $ commandProcessor d 2
forkIO $ commandProcessor d 3
forkIO $ commandProcessor d 4
forkIO (threadDelay 1000 >> putStrLn "Hello World?")
threadDelay 10000
return ()
commandProcessor :: TVar (Map.Map String Int)-> Int-> IO ()
commandProcessor d i= do
addCommand d i
commandProcessor d i
addCommand :: TVar (Map.Map String Int) ->Int -> IO ()
addCommand d i = do
succ <- atomically $ runAdd d
putStrLn $"Result of add in " ++ (show i)++ " " ++( show succ)
runAdd d =do
dl <- readTVar d
let (succ,g)= if Map.member "a" dl
then
(False,dl)
else
(True,Map.insert "a" 9 dl)
writeTVar d g
return succ
La salida de muestra sería así:
Resultado de add en 1 Verdadero resultado de add en 4 resultado falso de add en 1 falseresult of add en 2 falseresult of add in 3 false hello world? Resultado de agregar en 4 falsos
Resultado de add en 1 falseresult of add en 2 resultado falso de add en 3 resultado falso de add en 4 falso
Resultado de add en 1 resultado falso de add en 2 falseresult of add en 3 falseresult of add en 4 falso
Resultado de add en 1 resultado falso de add en 2 falseresult of add en 3 falseresult of add en 4 falso
Resultado de add en 1 resultado falso de add en 2 falseresult of add en 4 falseresult of add en 3 falso
Resultado de add en 1 resultado falso de add en 4 falseresult of add en 2 falseresult of add en 3 falso
Resultado de add en 1 falseresult of add en 4 resultado falso de add en 2 resultado falso de add en 3 falso
Resultado de add en 1 falseresult of add in 4 false
Resultado de add en 2 falseresult of add in 3 false
Resultado de add en 1 falseresult of add in 4 false
Resultado de add en 2 falseresult of add en 3 resultado falso de add en 1 resultado falso de add en 4 falso
Resultado de add en 2 falseresult of add in 3 false
Resultado de add en 1 falseresult of add in 4 false
Cuando leí atómicamente
. Esto significa que todas las operaciones dentro de la transacción completamente completadas, sin ningún otro hilo que modifique las variables que nuestra transacción está usando o falla, y el estado se vuelve a donde estaba antes de que se iniciara la transacción. En resumen, las transacciones atómicas se completan por completo, o es como si nunca se ejecutaran en absoluto.
Entonces, a la pregunta, ¿podría el "retorno" de Succ en algunos casos nunca ocurrir? Es decir, ¿podría la línea succ <- atómicamente $ runadd d putstrln $ "resultado de agregar" ++ (show i) ++ "" ++ (show succ)
Dé una salida de "resultado de agregar? I" ("como si nunca se ejecutaran en absoluto")
Solución
Si una transacción se retrocede, lo que sucede es que su programa lo intenta nuevamente. Puedes imaginar la implementación de atomically
ser algo como esto:
atomically action = do varState <- getStateOfTVars
(newState, ret) <- runTransactionWith action varState
success <- attemptToCommitChangesToTVars newState
if success
then return ret
else atomically action -- try again
En su caso, la transacción siempre se ejecutará y siempre se completará. Puede completarse en el segundo o tercer intento debido a los conflictos, pero eso es invisible para usted, el usuario. STM se asegura de que la acción ocurra atómicamente, incluso si lleva algunos vale antes de que pueda hacerlo con éxito.
Otros consejos
threadDelay
ya devuelve (), no es necesario explícitamentereturn ()
despuésnewTVarIO
es una versión concisa deatomically . newTVar
.- Es más legible si usas
forever
en lugar de llamar a ti mismo como se hace encommandProcessor
.
En cuanto a su pregunta, la respuesta es "sí". Se llama Live-Lock en el que su hilo tiene trabajo por hacer, pero no puede progresar. Imagina una función realmente costosa, expensive
, y una función realmente barata, cheap
. Si estos operan en competir atomically
Bloques en el mismo TVar
entonces la función barata puede causar el expensive
función para nunca completar. Construí un ejemplo para un Relacionado So Pregunta.
Sin embargo, su ejemplo de cierre no está del todo correcto, si la operación STM nunca se completa, entonces putStrLn
Nunca se alcanzará y no se verá ninguna salida desde ese hilo.