[英]How would I pipe with a timeout that resets with each incoming?
The withTimeout
function is suppose to pipe ConsoleEvent
with a CeTimeout
sent every s :: Int
seconds if nothing has been received. withTimeout
函数假设管道ConsoleEvent
,如果没有收到任何内容,则每隔s :: Int
秒发送一次CeTimeout
。 Instead it fails to send the CeTimeout
events at the appropriate times. 相反,它无法在适当的时间发送
CeTimeout
事件。 One CeTimeout
event is replaced for other events if greater than s
seconds have passed with the original event being lost. 如果大于
s
秒且原始事件丢失,则会将一个CeTimeout
事件替换为其他事件。 Also instead of one CeTimeout
event, it should be n*s
CeTimeout
events with n
counting for each s
second period that has passed. 此外,而不是一个
CeTimeout
事件,应该是n*s
CeTimeout
与事件n
每个计数s
已经过去了2期。 Where is the mistake, and what would be the correction? 错误在哪里,纠正是什么? Thanks!
谢谢!
withTimeout :: (MonadIO t) => Int -> Pipe ConsoleEvent ConsoleEvent t ()
withTimeout ((* 1000000) -> s) = join . liftIO $ work
where
work :: (MonadIO t) => IO (Pipe ConsoleEvent ConsoleEvent t ())
work =
do
(oSent, iKept) <- spawn $ bounded 1
(oKept, iSent) <- spawn $ unbounded
(oTimeout, iTimeout) <- spawn $ bounded 1
tid <- launchTimeout oTimeout >>= newMVar
forkIO $ do
runEffect . forever $ fromInput iKept >-> factorTimeout tid oTimeout >-> toOutput oKept
forkIO $ do
runEffect . forever $ fromInput iTimeout >-> toOutput oKept
return $ do
await >>= (liftIO . guardedSend oSent)
(liftIO . guardedRecv $ iSent) >>= yield
guardedSend :: Output ConsoleEvent -> ConsoleEvent -> IO ()
guardedSend o ce =
(atomically $ send o ce) >>= \case
True -> return ()
otherwise -> die $ "withTimeout can not send"
guardedRecv :: Input ConsoleEvent -> IO ConsoleEvent
guardedRecv i =
(atomically $ recv i) >>= \case
Just a -> return a
otherwise -> die $ "withTimeout can not recv"
launchTimeout :: Output ConsoleEvent -> IO ThreadId
launchTimeout o =
forkIO . forever $ do
threadDelay $ s
(atomically $ send o CeTimeout) >>= \case
True -> return ()
otherwise -> die "withTimeout can not send timeout"
relaunchTimeout :: Output ConsoleEvent -> ThreadId -> IO ThreadId
relaunchTimeout o oldTid =
do
tid <- launchTimeout o
killThread oldTid
return tid
factorTimeout :: MVar ThreadId -> Output ConsoleEvent -> Pipe ConsoleEvent ConsoleEvent IO ()
factorTimeout v o =
do
ce <- await
liftIO . modifyMVar_ v $ relaunchTimeout o
yield ce
It seems like a Pipe
will only allow one yield
per await
. 这似乎是一个
Pipe
将只允许一个yield
每await
。 This means that a CeTimeout
can not arbitrarily be sent down the pipe because nothing came into the pipe to cause the flow. 这意味着
CeTimeout
不能随意向管道发送,因为没有任何东西进入管道导致流动。 I will have to go through the source to confirm this; 我将不得不通过消息来源证实这一点; in the meantime this function has been refactored to return a
Pipe
and a Producer
instead of just a Pipe
. 与此同时,此函数已重构为返回
Pipe
和Producer
而不仅仅是Pipe
。 The Producer
can then be joined back in the calling function. 该
Producer
然后可以在调用函数中加入回来。 The initial plan was to return just a Pipe
so that the calling function would not have to do any additional work to make timeouts work. 最初的计划是只返回一个
Pipe
这样调用函数就不需要做任何额外的工作来使超时工作。 That would have been a more self contained solution. 那本来是一个更独立的解决方案。 This alternative is nice in that it is more explicit.
这个替代方案很好,因为它更明确。 The timeouts won't look like they are appearing out of thin air to someone that is not familiar with the pipeline.
对于不熟悉管道的人来说,超时看起来并不像是显得空洞。
withTimeout :: (MonadIO t) => Int -> IO (Pipe ConsoleEvent ConsoleEvent t (), Producer ConsoleEvent t ())
withTimeout ((* 1000000) -> s) =
do
(oTimeout, iTimeout) <- spawn $ bounded 1
vTid <- launchTimeout oTimeout >>= newMVar
return (factorTimeout vTid oTimeout, fromInput iTimeout)
where
launchTimeout :: Output ConsoleEvent -> IO ThreadId
launchTimeout o =
forkIO . forever $ do
threadDelay $ s
(atomically $ send o CeTimeout) >>= \case
True -> return ()
otherwise -> die "withTimeout can not send timeout"
relaunchTimeout :: Output ConsoleEvent -> ThreadId -> IO ThreadId
relaunchTimeout o oldTid =
do
tid <- launchTimeout o
killThread oldTid
return tid
factorTimeout :: (MonadIO t) => MVar ThreadId -> Output ConsoleEvent -> Pipe ConsoleEvent ConsoleEvent t ()
factorTimeout v o =
do
ce <- await
liftIO . modifyMVar_ v $ relaunchTimeout o
yield ce
main :: IO ()
main =
do
hSetBuffering stdin NoBuffering
hSetEcho stdin False
exitSemaphore <- newEmptyMVar
(o1, i1) <- spawn $ bounded 1
(o2, i2) <- spawn $ bounded 1
(timeoutTrap, timeoutRender) <- withTimeout 2
runEffect $ yield CeBegan >-> toOutput o1
forkIO $ do
runEffect . forever $ chars >-> toOutput o1
putMVar exitSemaphore ()
-- other inputs would be piped to o1 here
forkIO $ do
runEffect . forever $ fromInput i1 >-> timeoutTrap >-> toOutput o2
putMVar exitSemaphore ()
forkIO $ do
runEffect . forever $ timeoutRender >-> toOutput o2
putMVar exitSemaphore ()
forkIO $ do
-- logic would be done before dumpPipe
runEffect . forever $ fromInput i2 >-> dumpPipe >-> (await >> return ())
putMVar exitSemaphore ()
takeMVar exitSemaphore
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.