2015-08-09 57 views
2

我的主函數有一個無限循環,我想每100毫秒執行一次循環。我知道這是通過一些並行或並行的方法完成的,但我從來沒有做過這樣的事情,甚至不知道從哪裏開始。你將如何實現這樣的功能?指定無限循環的毫秒速度

回答

8

假設你的循環體需要可以忽略不計的時候,只需要使用threadDelayControl.Concurrent

import Control.Concurrent 

main = forever $ do 
    mainBody 
    threadDelay (100*1000) -- value in microseconds 

更新:爲了解決您的循環體的時候,用這個:

import Data.Time.Clock 
import Control.Concurrent 
import Control.Monad 

mainBody :: IO() 
mainBody = putStrLn "hi" 

main = forever $ do 
    start <- getCurrentTime 
    mainBody 
    end <- getCurrentTime 
    let diff = diffUTCTime end start 
     usecs = floor (toRational diff * 1000000) :: Int 
     delay = 100*1000 - usecs 
    if delay > 0 
    then threadDelay delay 
    else return() 
+0

謝謝你的回答,但循環體需要不同的時間。一個可能需要80毫秒,另一個可能需要0。我想平均匹配所有的時間長度。 –

+0

謝謝你的更新:) –

1

您可以使用sleep在每次迭代結束時暫停循環100毫秒。 https://www.haskell.org/hoogle/?q=sleep

+1

但請注意警告:_Warning:此函數有幾個缺點......_最好是從Control.Concurrent使用'threadDelay'。 – ErikR

+0

@ user5402小心展開? – AJFarmar

+0

對不起,延遲迴復。好的觀察,我沒有想到這一點,雖然我不是Haskell的專家@ user5402 –

3

Haskell的主題重量輕,所以快速解決方案是在每個週期進行分岔。因此,您最終將使用主線程作爲工作線程的管理器,這可以確保每100個微工生成一個工人。

import Control.Concurrent 

main = 
    forever $ do 
    forkIO $ loopCycle 
    threadDelay $ 100 * 10^3 

如果你關心的異常不迷路,並在主線程中得到重新拋出相反,我建議考慮看看the "slave-thread" package。其實,我建議使用這個軟件包,而不是forkIO和默認的兄弟,但是我是作者,所以我可能是主觀的。

另請注意,上述解決方案可能會導致工作線程累積,以防loopCycle需要比100微秒更長的執行時間。爲了防止出現這種情況,您可以在經理線程中實施策略,以確保活動員工的數量有限。以下是如何實現這樣一個策略:

-- From the "SafeSemaphore" package 
import qualified Control.Concurrent.SSem as Sem 

main = 
    manager 12 (100 * 10^3) $ putStrLn "Implement me!" 

manager :: Int -> Int -> IO() -> IO() 
manager limit delay worker = 
    do 
    sem <- Sem.new limit 
    forever $ do 
     forkIO $ Sem.withSem sem $ worker 
     threadDelay delay 
+0

我會檢查圖書館。謝謝你的主意! –

+0

「在經理線程中實施策略,這將確保活動員工數量有限」如何?使用哪些功能?有些指針會有幫助... –

+0

@WillNess請參閱更新。 –