gpt4 book ai didi

haskell - 如何每秒强制评估 X 次?

转载 作者:行者123 更新时间:2023-12-04 15:17:20 25 4
gpt4 key购买 nike

我需要一个实时事件循环来做这样的事情:

myEventLoop = do
businessLogic x0 x1 x2 ... xN
sleep 0.01
myEventLoop

我知道 eventloop 包,但它似乎更适合 Web 应用程序,而我需要的是实时信号处理。假设采样率为 100 Hz。采样率不需要非常精确;如果偶尔只有 98 Hz,那没什么大不了的。但我从不希望它偏离超过 5%。目前我们只讨论 GHC 执行 +/-5%。忽略操作系统引起的计时错误。

我的问题是:
1)这是Haskell可以做的事情吗?我有点担心 +/- 5% 的部分。
2) sleep 部分效率低吗?或者当 myEventLoop 正在执行 sleep 部分时,其他 Haskell 线程是否可以占用同一个 OS 线程?
3)假设 sleep 是个好主意,那么硬编码 sleep 时间很可能不是。我可以读取时间戳计数器 (TSC),因为该程序在 x86 架构上运行,但如果 GHC 决定将程序拆分为微线程,将一些发送到 1 个 CPU 内核,将其他发送到不同的 CPU 内核,这种方法可能会出现问题,因为不同的内核可以有不同的 TSC 值。这是我应该担心的事情吗?如果是,有什么更好的方法?

提前致谢

最佳答案

你可以试试,但我并不乐观。 GC 和 RTS 会对您产生重大的负面影响,但我无法说您是否会在意。

Eventloop 是......巨大的......我个人会做一些定制和轻量级的事情。

不要使用“ sleep 然后逻辑”设置,因为“逻辑”部分不是免费的,您最终会遇到比预期更长的暂停。我的“fork logic then sleep”测试显示出类似的不良行为,因为 sleep在 RTS 再次调度父线程之前不会启动。

使用绝对时间避免漂移的自定义解决方案

自定义解决方案如下所示:

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

periodic :: NominalDiffTime -> UTCTime -> IO () -> IO ()
periodic delayTime base operation =
do start <- getCurrentTime
let end = addUTCTime delayTime base
microSeconds = floor $ (1000000 :: Double) * realToFrac (diffUTCTime end start)
threadDelay microSeconds
void $ forkIO operation
periodic delayTime end operation

main :: IO ()
main =
do start <- getCurrentTime
forkIO $ periodic (1/98) start (getCurrentTime >>= print)
threadDelay 10000000 -- 10 seconds

这很简单,并且可以让您真正接近任何框架将提供的功能,除非您需要一些时髦的功能,例如取消事件。你也接近你想要的时期:
import Control.Concurrent
import Control.Monad
import Data.Time

periodic :: NominalDiffTime -> UTCTime -> IO () -> IO ()
periodic delayTime base operation =
do start <- getCurrentTime
let end = addUTCTime delayTime base
microSeconds = floor $ (1000000 :: Double) * realToFrac (diffUTCTime end start)
threadDelay microSeconds
void $ forkIO operation
periodic delayTime end operation

main :: IO ()
main =
do start <- getCurrentTime
forkIO $ periodic (1/98) start (getCurrentTime >>= print)
threadDelay 10000000 -- 10 seconds

结果是:
% ./y | wc -l
980

你可以分析打印的时间来获得你的置信区间,但是随着负载的变化、堆的增长和 GC 需要做更多的暂停,这会变得更糟。

实际答案

编辑,因为您有实际问题。

1) Is this the kind of thing Haskell can do?



这并不是 Haskell 真正适合的东西——GHC RTS 甚至不适合像音频这样的软实时工作。

2) Is the sleep part inefficient? Or can other Haskell threads occupy the same OS thread while myEventLoop is executing the sleep part?



多个 Haskell 线程可以占用同一个 OS 线程,没有问题。

3) Assuming sleeping is a good idea, hard coding the sleep time most likely is not. I can read the time stamp counter (TSC) since the program is running on an x86 architecture, but that approach could be problematic if GHC decides to chop up the program into microthreads, sending some to 1 CPU core and others to a different CPU core, as different cores can have different values for TSC. Is this a thing I should be worried about, and if so, what is a better approach?



是的,您应该担心让 Haskell 线程从核心移动到核心以及 OS 线程移动到 OS 线程。以上是我对本土方法的尝试。十一年前我写了 control-event (关于 hackage)为我解决同样的问题,但我的时间限制不是问题,需要有点不同。这些天来,您可以直接使用 GHC 事件管理器,但由于 API 级别较低,我会避免使用它,并且它不能解决您的 GC 暂停问题。

关于haskell - 如何每秒强制评估 X 次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56190913/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com