這是嘗試制作一段簡單的代碼,該代碼將獲取當前時間并假設時間合適時觸發一個函式。
{-# LANGUAGE BlockArguments, NumericUnderscores #-}
module Main where
import Control.Concurrent
import Control.Monad (forever, forM, void)
import Data.Time.Clock
main :: IO ()
main = forever do
forkIO writer
threadDelay 1_000_000
writer :: IO ()
writer = print =<< getCurrentTime
得到這個:
2021-12-13 09:22:08.7632491 UTC
2021-12-13 09:22:09.7687358 UTC
2021-12-13 09:22:10.7756821 UTC
2021-12-13 09:22:11.7772306 UTC
2021-12-13 09:22:12.7954329 UTC
2021-12-13 09:22:13.8096189 UTC
2021-12-13 09:22:14.8218579 UTC
2021-12-13 09:22:15.826626 UTC
2021-12-13 09:22:16.8291541 UTC
2021-12-13 09:22:17.8358406 UTC
2021-12-13 09:22:18.8468617 UTC
2021-12-13 09:22:19.8490381 UTC
2021-12-13 09:22:20.859682 UTC
2021-12-13 09:22:21.868705 UTC
2021-12-13 09:22:22.88392 UTC
2021-12-13 09:22:23.8893969 UTC
2021-12-13 09:22:24.8940725 UTC
2021-12-13 09:22:25.9026013 UTC
2021-12-13 09:22:26.9181843 UTC
2021-12-13 09:22:27.920115 UTC
2021-12-13 09:22:28.9214061 UTC
2021-12-13 09:22:29.9236218 UTC
2021-12-13 09:22:30.9320501 UTC
2021-12-13 09:22:31.9359116 UTC
2021-12-13 09:22:32.9381218 UTC
2021-12-13 09:22:33.9541171 UTC
2021-12-13 09:22:34.9639691 UTC
2021-12-13 09:22:35.9767943 UTC
2021-12-13 09:22:36.9909998 UTC
2021-12-13 09:22:38.0016628 UTC
2021-12-13 09:22:39.0029746 UTC
2021-12-13 09:22:40.01921 UTC
2021-12-13 09:22:41.0337936 UTC
2021-12-13 09:22:42.0369494 UTC
2021-12-13 09:22:43.0403321 UTC
2021-12-13 09:22:44.0426835 UTC
2021-12-13 09:22:45.0468416 UTC
2021-12-13 09:22:46.0503551 UTC
2021-12-13 09:22:47.0557148 UTC
2021-12-13 09:22:48.066979 UTC
2021-12-13 09:22:49.0723431 UTC
正如您可能已經注意到的那樣,差異并不準確,在我的情況下,timedif 中的錯誤可能至關重要。有什么方法可以改善這種情況嗎?
當不同的執行緒采用列印功能時嘗試了該選項,但從長遠來看幾乎沒有區別。
謝謝!
uj5u.com熱心網友回復:
現在,這是您最初問題的答案。秘訣是不要總是在事件之間等待一秒鐘,您應該跟蹤觸發時間,始終將其增加一秒,然后等待到達下一個觸發時間所需的任何時間。它實際上在許多方面與我的其他答案相似:
{-# LANGUAGE NumericUnderscores #-}
module Main where
import Control.Concurrent
import Control.Monad
import Data.Time
main :: IO ()
main = everySecond =<< getCurrentTime
everySecond :: UTCTime -> IO ()
everySecond tick = do
forkIO writer
-- next tick in one second
let nexttick = addUTCTime (secondsToNominalDiffTime 1) tick
now <- getCurrentTime
let wait = nominalDiffTimeToSeconds (diffUTCTime nexttick now)
threadDelay $ ceiling (wait * 1_000_000)
everySecond nexttick
writer :: IO ()
writer = print =<< getCurrentTime
示例輸出:
2021-12-13 21:16:53.316687476 UTC
2021-12-13 21:16:54.318070692 UTC
2021-12-13 21:16:55.31821399 UTC
2021-12-13 21:16:56.318432887 UTC
2021-12-13 21:16:57.318432582 UTC
2021-12-13 21:16:58.318648861 UTC
2021-12-13 21:16:59.317988137 UTC
2021-12-13 21:17:00.318367675 UTC
2021-12-13 21:17:01.318565036 UTC
2021-12-13 21:17:02.317856019 UTC
2021-12-13 21:17:03.318285608 UTC
2021-12-13 21:17:04.318508451 UTC
2021-12-13 21:17:05.318487069 UTC
2021-12-13 21:17:06.318435325 UTC
2021-12-13 21:17:07.318504691 UTC
2021-12-13 21:17:08.318591666 UTC
2021-12-13 21:17:09.317797443 UTC
2021-12-13 21:17:10.317732578 UTC
2021-12-13 21:17:11.318100396 UTC
2021-12-13 21:17:12.318535002 UTC
2021-12-13 21:17:13.318008916 UTC
2021-12-13 21:17:14.317803441 UTC
2021-12-13 21:17:15.318220664 UTC
2021-12-13 21:17:16.318558786 UTC
2021-12-13 21:17:17.31793816 UTC
2021-12-13 21:17:18.322564881 UTC
2021-12-13 21:17:19.318923334 UTC
2021-12-13 21:17:20.318293808 UTC
uj5u.com熱心網友回復:
不能完全回答您的問題,但是如果您想撰寫一個程式來在特定時間觸發事件,則更強大的設計是:
- 按時間對(時間,事件)對串列進行排序
- 睡眠串列中的第一個事件時間與當前時間之間的差異
- 當您醒來時,獲取/更新當前時間,并執行并從串列前面洗掉所有時間已“過期”的事件(即,當前時間或之前的事件時間)。
- 如果串列仍然非空,則跳到第 2 步。
這避免了每秒輪詢的需要(這可能不是什么大問題,但仍然......)并避免了由于您比預期醒來晚而錯過事件的可能性。
下面是一個示例程式。(該程式依賴于threadDelay將負數視為零,以防事件需要很長時間才能運行,并且實際時間超過了第一個未到期的事件。)
{-# LANGUAGE NumericUnderscores #-}
import Data.List
import Data.Time
import Control.Concurrent
data Event = Event
{ eventTime :: UTCTime
, eventAction :: IO ()
}
runEvents :: [Event] -> IO ()
runEvents = go . sortOn eventTime
where go [] = return () -- no more events
go events@(Event firstTime _ : _) = do
now <- getCurrentTime
let wait = nominalDiffTimeToSeconds (diffUTCTime firstTime now)
threadDelay $ ceiling (wait * 1_000_000)
now' <- getCurrentTime
let (a, b) = span (expiredAsOf now') events
mapM eventAction a -- run the expired events
go b -- wait for the rest
expiredAsOf t e = eventTime e <= t
main = do
-- some example events
now <- getCurrentTime
let afterSeconds = flip addUTCTime now . secondsToNominalDiffTime
evts = [ Event (afterSeconds 3) (putStrLn "3 seconds")
, Event (afterSeconds 6) (putStrLn "6 seconds action # 1")
, Event (afterSeconds 6) (putStrLn "6 seconds action # 2")
, Event (afterSeconds 7) (putStrLn "Done after 7 seconds")
]
runEvents evts
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/382675.html
