E 'sicuro per far scattare l'azione del fuoco inIn banana reattiva, è sicuro attivare azioni del gestore da più thread?
(addHandler, fire) <- newAddHandler
da un thread diverso da cui è stato compilato il grafico reattivo-banane?
E 'sicuro per far scattare l'azione del fuoco inIn banana reattiva, è sicuro attivare azioni del gestore da più thread?
(addHandler, fire) <- newAddHandler
da un thread diverso da cui è stato compilato il grafico reattivo-banane?
Sì, questo è sicuro, ma c'è l'avvertenza che @Cirdec ha menzionato.
Per conreteness, si consideri il seguente esempio che crea una rete di eventi mediante la addHandler
in un thread separato e quindi chiama fire
più volte nel thread principale
import Control.Concurrent (myThreadId, threadDelay, forkIO)
main = do
...
(addHandler, fire) <- newAddHandler
let networkDescription :: MomentIO()
networkDescription = do
e <- fromAddHandler addHandler
...
reactimate $ (print =<< myThreadId) <$ e -- reactimate
forkIO $ do
network <- compile networkDescription
actuate network
...
forever $ do -- event loop
threadDelay (10^6)
fire()
(Vedere la documentazione "Terminating the program" in Control.Concurrent per il motivo per cui ho messo . il ciclo degli eventi nel thread principale in contrasto con la realizzazione della rete nel thread principale)
in questa e simili situazioni, il seguente conterrà:
reactimate
verranno eseguite nella thread che chiama fire
, non nel thread in cui è stata compilata la rete. Questo è ciò che @Cirdec ha già menzionato.fire
, potrebbe potenzialmente intercalarsi con altre chiamate a fire
, ad esempio il programma potrebbe chiamare lo fire
due volte contemporaneamente. Quindi,
Time -> a
e liste [(Time,a)]
come al solito.reactimate
s possono essere interlacciate. In altre parole, la parte FRP pura rimarrà pura, ma l'IO effettivo è soggetto alla concorrenza come al solito.L'esecuzione del gestore fire
è sicura; legge uno IORef
che viene aggiornato atomicamente e esegue ciascuno dei gestori aggiunti nel thread corrente. Indipendentemente dal fatto che sia sicuro dipenderà da quali gestori sono stati aggiunti allo addHandler
.
L'utilizzo di addHandler
in interpretAsHandler
, fromAddHandler
o fromChanges
deve essere sicuro. Nulla di ciò che conosco in banana reattiva ha alcuna affinità con i thread, e anche se fosse così, questi sono i motivi per cui è stato creato newAddHandler
, quindi dovrebbe essere comunque sicuro.
Quello che devi fare attenzione è le azioni IO()
eseguite da reactimate
. Se è necessario riattivare le azioni IO
che devono essere eseguite in un thread specifico (per OpenGL output, ecc.), È necessario produrre solo azioni IO()
che invieranno i loro dati a quel thread. In questo complete OpenGL example for reactive-banana le azioni IO()
per l'output OpenGL, che hanno affinità di thread, vengono eseguite nel thread OpenGL. Invece di reactimate
ing del Event (IO())
eseguirli direttamente sono aggiunti a un IORef
whenIdleRef <- newIORef (return())
let
addWhenIdle :: IO() -> IO()
addWhenIdle y = atomicModifyIORef' whenIdleRef (\x -> (x >> y,()))
runWhenIdle :: IO()
runWhenIdle = atomicModifyIORef' whenIdleRef (\x -> (return(), x)) >>= id
let networkDescription :: forall t. Frameworks t => Moment t()
networkDescription = do
reactimate $ fmap addWhenIdle (whenIdle outputs)
^ ^
| Event (IO())
Stuff the event into an IORef
Il IORef
un'azienda IO()
azioni da eseguire è leggere e ciascuna di tutte le azioni vengono eseguite in un contesto che so è in OpenGL filo.
idleCallback $= Just (do -- will be executed in the OpenGL thread when it's idle
getCurrentTime >>= raiseTime
runWhenIdle -- run those `IO()` actions in this thread
postRedisplay Nothing)
Ciò rende molto chiaro. –