【问题标题】:Haskell: Reading from /proc. Issues with strictness and laziness. Process statisticsHaskell:从 /proc 读取。严格和懒惰的问题。进程统计
【发布时间】:2012-04-28 09:03:58
【问题描述】:

从 /proc 读取文件时我的行为很奇怪 如果我用 prelude 的 readFile 懒惰地阅读 /proc/pid/stat - 它可以工作,但不是我想要的方式。 使用 Data.ByteString.readFile 切换到严格阅读会给我一个空字符串。

我这里需要严格阅读,以便能够在短时间内比较两次阅读的结果。

因此使用 System.IO.readFile 读取 /proc/pid/stat 根本不起作用。它在 0.5 秒的间隔内给了我相同的结果。我认为这是由于懒惰和半封闭手柄或其他原因... 打开和关闭文件句柄显式有效。

h <- openFile "/proc/pid/stat" ReadMode
st1 <- hGetLine h; hClose h

但是,如果我们有严格的字节串阅读,为什么还要这样做。对吧?

这就是我卡住的地方。

import qualified Data.ByteString as B
B.readFile "/proc/pid/stat" >>= print

这总是返回一个空字符串。也在 GHCI 中进行了测试。 有什么建议。谢谢。

--- 更新 ---

感谢丹尼尔的建议。

这是我真正需要做的。这可能有助于全面展示我的困境并带来更一般的建议。

我需要计算进程统计信息。这里以部分代码(只是CPU使用率)为例。

cpuUsage pid = do
  st1 <- readProc $ "/proc" </> pid </> "stat"
  threadDelay 500000 -- 0.5 sec
  st2 <- readProc $ "/proc" </> pid </> "stat"
  let sum1 = (read $ words st1 !! 13) +
             (read $ words st1 !! 14)
      sum2 = (read $ words st2 !! 13) +
             (read $ words st2 !! 14)
  return $ round $ fromIntegral (sum2 - sum1) * jiffy / delay * 100
  where
    jiffy = 0.01
    delay = 0.5
    readProc f = do
      h <- openFile f ReadMode
      c <- hGetLine h
      hClose h
      return c
  1. Prelude.readFile 由于懒惰而无法工作
  2. ByteString 中的严格函数不起作用。谢谢丹尼尔的解释。
  3. 如果我将整个计算填入其中,withFile 将起作用(它会正确关闭句柄),但由于计算需要时间,因此间隔不会严格为 0.5。
  4. 显式打开和关闭句柄并使用 hGetContents 不起作用!出于同样的原因 readFile 没有。

在这种情况下唯一有效的方法是在上面的代码 sn-p 中使用 hGetLine 显式打开和关闭句柄。但这还不够好,因为某些 proc 文件不止一行,例如 /proc/meminfo。

所以我需要一个可以严格读取整个文件的函数。类似于 hGetContents 但严格的东西。

我试图这样做:

readProc f = do
  h <- openFile f ReadMode
  c <- hGetContents h
  let c' = lines c
  hClose h
  return c'

希望这些行会触发它完整读取文件。没有运气。仍然得到一个空列表。

任何帮助,建议非常感谢。

【问题讨论】:

    标签: linux haskell system


    【解决方案1】:

    ByteString 代码是

    readFile :: FilePath -> IO ByteString
    readFile f = bracket (openBinaryFile f ReadMode) hClose
        (\h -> hFileSize h >>= hGet h . fromIntegral)
    

    但是/proc/whatever不是真正的文件,它是按需生成的,当你stat他们获取文件大小时,你得到0。所以ByteStringreadFile成功读取了0字节。

    【讨论】:

    • 好的。现在有点清楚了。那么在这种情况下有什么解决办法呢?我需要在 0.5 秒的间隔内读取统计文件。懒惰只会扼杀节目。我只需要明确地打开和关闭文件句柄吗?谢谢。
    • 我认为你必须明确地打开和关闭。虽然也许你可以打开一次并保持打开状态。无论如何,我认为hGetNonBlocking 是要走的路。 hGetNonBlocking k 尝试读取 k 字节,如果可用的较少,则需要。或hGetLine.
    【解决方案2】:

    在编码这种类型的东西之前,通常最好检查一下 Hackage 上是否已经存在某些东西。在这种情况下,我找到了procstat 包,它似乎工作得很好:

    import System.Linux.ProcStat
    
    cpuUsage pid = do
      Just before <- fmap procTotalTime <$> procStat pid
      threadDelay 500000 -- 0.5 sec
      Just after  <- fmap procTotalTime <$> procStat pid
      return . round $ fromIntegral (after - before) * jiffy / delay * 100
      where
        procTotalTime info = procUTime info + procSTime info
        jiffy = 0.01
        delay = 0.5
    

    【讨论】:

    • 有趣...谢谢。您知道学习时的感觉,您只想尝试自己做事。不过我应该看看。
    猜你喜欢
    • 2015-09-06
    • 1970-01-01
    • 1970-01-01
    • 2016-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多