2015-08-09 3 views
2

Моя основная функция имеет один бесконечный цикл, и я хотел бы выполнить каждый цикл из них каждые 100 миллисекунд. Я знаю, что это делается с помощью параллельного или параллельного метода, но я никогда раньше этого не делал и понятия не имел, с чего начать. Как бы вы реализовали такую ​​функцию?Укажите миллисекунду скорости бесконечного цикла

ответ

8

Предполагая, что ваше тело цикла занимает незначительное время, просто используйте threadDelay из Control.Concurrent:

import Control.Concurrent 

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

Update: Для учета времени вашего тела цикла, используйте:

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: Эта функция имеет несколько недостатков ..._ Это лучше использовать 'threadDelay' из Control.Concurrent. – ErikR

+0

@ user5402 хотите расширить? – AJFarmar

+0

Извините за поздний ответ. Хорошее наблюдение, я не думал об этом, хотя я не специалист по Haskell @ user5402 –

3

темы Хаскеля являются легкими, поэтому быстрое решение будет заключаться в вилке на каждом цикле. Таким образом, вы в конечном итоге будете использовать основной поток в качестве менеджера рабочих потоков, который гарантирует, что рабочий будет порожден каждые 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 Пожалуйста, просмотрите обновления. –

Смежные вопросы