1{-# LANGUAGE FlexibleContexts #-}
4-- Module : Streamly.Time
5-- Copyright : (c) 2017 Harendra Kumar
8-- Maintainer : harendra.kumar@gmail.com
9-- Stability : experimental
12-- Time utilities for reactive programming.
23import Control.Concurrent (threadDelay)
24import Control.Monad (when)
25import Control.Monad.IO.Class (MonadIO(liftIO))
26import Data.Maybe (fromJust, isJust)
28import Streamly (parallel)
29import Streamly.SVar (MonadAsync)
30import Streamly.Streams.StreamK (IsStream(..))
31import Streamly.Fold (Fold)
33import qualified Streamly.Fold as FL
34import qualified Streamly.Prelude as S
36-- | Run an action forever periodically at the given frequency specified in per
40{-# DEPRECATED periodic "Please use the \"rate\" combinator instead" #-}
41periodic :: Int -> IO () -> IO ()
42periodic freq action = do
44 threadDelay (1000000 `div` freq)
47-- | Run a computation on every clock tick, the clock runs at the specified
48-- frequency. It allows running a computation at high frequency efficiently by
49-- maintaining a local clock and adjusting it with the provided base clock at
50-- longer intervals. The first argument is a base clock returning some notion
51-- of time in microseconds. The second argument is the frequency in per second
52-- (Hz). The third argument is the action to run, the action is provided the
53-- local time as an argument.
56{-# DEPRECATED withClock "Please use the \"rate\" combinator instead" #-}
57withClock :: IO Int -> Int -> (Int -> IO ()) -> IO ()
58withClock clock freq action = do
60 go t period period t 0
64 period = 1000000 `div` freq
66 -- Note that localTime is roughly but not exactly equal to (lastAdj + tick
67 -- * n). That is because we do not abruptly adjust the clock skew instead
68 -- we adjust the tick size.
69 go lastAdj delay tick localTime n = do
71 when (delay > 0) $ threadDelay delay
75 (t, newTick, newDelay) <- adjustClock lastAdj localTime delay
76 go t newDelay newTick (localTime + newTick) 0
77 else go lastAdj delay tick (localTime + tick) (n + 1)
79 -- Adjust the tick size rather than the clock to avoid abrupt changes
80 -- resulting in jittery behavior at the end of every interval.
81 adjustClock lastAdj localTime delay = do
83 let newTick = period + (baseTime - localTime) `div` freq
84 lastPeriod = (baseTime - lastAdj) `div` freq
85 newDelay = max 0 (delay + period - lastPeriod)
86 return (baseTime, newTick, newDelay)
88-------------------------------------------------------------------------------
89-- Stream element unaware: Time based buffering
90-------------------------------------------------------------------------------
92-- There are two ways in which time based buffering can be implemented.
94-- 1) One is to use an API like groupsOf to group elements by time and then
95-- flush when the group is complete. This will require checking time on each
98-- 2) Use an async thread to write. The producer thread would just queue the
99-- elements to be written on a queue associated with the writer thread. When
100-- the write thread is scheduled elements that have been buffered will be
101-- written based on a buffering policy. This will require the producer to
102-- synchronize on the queue, send a doorbell when the queue has items in it.
103-- The queue can be an array which can be written directly to the IO device.
105-- We can try both and see which one performs better.
107-- XXX add this example after fixing the serial stream rate control
108-- >>> S.toList $ S.take 5 $ intervalsOf 1 FL.sum $ constRate 2 $ S.enumerateFrom 1
111-- | Group the input stream into windows of @n@ second each and then fold each
112-- group using the provided fold function.
115{-# INLINE intervalsOf #-}
117 :: (IsStream t, MonadAsync m)
118 => Double -> Fold m a b -> t m a -> t m b
119intervalsOf n f m = FL.grouped (catMaybes f) s
121 s = S.map (\x -> (Just x, False)) m `parallel` S.repeatM timeout
123 liftIO $ threadDelay (round $ n * 1000000)
124 return (Nothing, True)
125 catMaybes = FL.lfilter isJust . FL.lmap fromJust
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list