8

从 /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 没有。

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

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

我试图这样做:

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

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

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

4

2 回答 2

5

ByteString代码是

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

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

于 2012-04-17T02:26:35.740 回答
5

在编码这种类型的东西之前,通常最好检查一下 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
于 2012-04-17T06:02:33.047 回答