Linux Ubuntu上Haskell(GHC)中的线程延迟问题
在我的一些机器上,我注意到GHC.Conc中threadDelay函数的奇怪行为。以下节目:Linux Ubuntu上Haskell(GHC)中的线程延迟问题,linux,haskell,ubuntu,Linux,Haskell,Ubuntu,在我的一些机器上,我注意到GHC.Conc中threadDelay函数的奇怪行为。以下节目: main = do print "start" threadDelay (1000 * 1000) print "done" 按预期运行需要1秒。另一方面,该计划: {-# LANGUAGE BangPatterns #-} import Control.Concurrent main = do print "start" loop 100
main = do print "start"
threadDelay (1000 * 1000)
print "done"
按预期运行需要1秒。另一方面,该计划:
{-# LANGUAGE BangPatterns #-}
import Control.Concurrent
main = do print "start"
loop 1000
print "done"
where loop :: Int -> IO ()
loop !n =
if n == 0
then return ()
else do threadDelay 1000
loop (n-1)
在我的两台机器上运行大约需要10秒,但在其他机器上运行大约需要1秒,正如预期的那样。(我用“-threaded”标志编译了上述两个程序。)下面是Threadscope的屏幕截图,显示每10毫秒只有一次活动:
另一方面,下面是我的一台机器上ThreadScope的屏幕截图,该程序总共耗时1秒:
类似的C程序:
#include <unistd.h>
#include <stdio.h>
int main() {
int i;
for (i=1; i < 1000; i++) {
printf("%i\n",i);
usleep(1000);
}
return 0;
}
以前是否有人遇到过此问题,如果是,如何解决此问题?我在所有机器上运行ghc 7.2.1 for Linux(x86_64),并且运行各种版本的Ubuntu。它在Ubuntu 10.04.2上运行不好,但在11.04上运行良好。
threadDelay
不是一个精确的计时器。它承诺你的线程将睡眠至少和它的论点所说的一样长,但它没有承诺更多。如果你想让某些事情周期性地发生,你就必须使用其他的东西。(我不确定是什么,但可能对您有用。)我怀疑您忘记了使用“-threaded”选项进行编译。(我曾经在6.12.3中这样做过一次,并且始终有30毫秒的线程延迟。)如上所述,threadDelay只提供一个保证,即您至少会等待您请求的时间。Haskell的运行时没有获得操作系统的特殊合作
除此之外,这是操作系统的最大努力
这可能值得为线程延迟测试您的结果。例如:
module Main where
import Control.Concurrent
import Data.Time
time op =
getCurrentTime >>= \ t0 ->
op >>
getCurrentTime >>= \ tf ->
return $! (diffUTCTime tf t0)
main :: IO ()
main =
let action tm = time (threadDelay tm) >>= putStrLn . show in
mapM action [2000,5000,10000,20000,30000,40000,50000] >>
return ()
在我的windows box上,这为我提供了:
0.0156098s
0.0156098s
0.0156098s
0.0312196s
0.0312196s
0.0468294s
0.0624392s
0.0156098s
0.0156098s
0.0156098s
0.0312196s
0.0312196s
0.0468294s
0.0624392s
这表明delay和getCurrentTime的组合具有15.6毫秒的分辨率。当我循环1000次延迟1000时,我会等待15.6秒,所以这只是线程的最小等待时间
在我的UbuntuBox(11.04,内核2.6.38-11)上,我获得了更高的精度(~100us)
您可以通过让程序更繁忙来避免时间问题,这样我们就不会切换上下文。无论哪种方式,我都建议您不要使用threadDelay进行计时,或者至少检查时间并在给定的瞬间执行任何操作
如果你愿意使用FFI,通过C实现的高精度睡眠可能对你有用,但代价是你需要使用绑定线程(至少对你的计时器是这样)
0.0156098s
0.0156098s
0.0156098s
0.0312196s
0.0312196s
0.0468294s
0.0624392s