2012-04-17 23 views
8

Tengo un comportamiento realmente extraño al leer archivos de/proc Si leo/proc/pid/stat perezosamente con readFile de preludio, funciona pero no de la manera que quiero. Cambiar a lectura estricta con Data.ByteString.readFile me da una cadena vacía.Haskell: Lectura de/proc. Problemas con rigor y pereza. Estadísticas de proceso

Necesito una lectura estricta aquí para poder comparar los resultados de dos lecturas dentro de un intervalo corto.

Así que usar System.IO.readFile para leer/proc/pid/stat simplemente no funciona. Me da el mismo resultado dentro de un intervalo de 0.5 segundos. Me imagino que esto se debe a la pereza y el mango medio cerrado o algo así ... Abrir y cerrar el identificador de archivo funciona explícitamente.

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

¿Pero por qué hacer lo anterior si tenemos la lectura estricta de la longitud de bytes? ¿Derecha?

Aquí es donde me quedé atascado.

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

Esto siempre devuelve una cadena vacía. También probado en GHCI. Cualquier sugerencia. Gracias.

--- --- ACTUALIZACIÓN

Gracias Daniel por sugerencias.

Esto es lo que realmente necesito hacer. Esto podría ayudar a mostrar mi dilema completo y traer más sugerencias generales.

Necesito calcular las estadísticas del proceso. Aquí hay una parte del código (solo el uso de la CPU) como ejemplo.

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 no funciona debido a la pereza
  2. funciones estrictas de ByteString no funcionan. Gracias Daniel por la explicación.
  3. withFile funcionaría (cierra el asa correctamente) si rellené todo el cálculo en él, pero luego el intervalo no será estrictamente 0.5 ya que los cálculos toman tiempo.
  4. ¡Abrir y cerrar identificadores explícitamente y usar hGetContents no funciona! Por la misma razón, readFile no lo hace.

Lo único que funciona en esta situación es abrir y cerrar explícitamente identificadores con hGetLine en el fragmento de código anterior. Pero esto no es lo suficientemente bueno ya que algunos archivos de proceso son más de una línea como/proc/meminfo.

Necesito una función que lea todo el archivo estrictamente. Algo así como hGetContents pero estricto.

yo estaba tratando de hacer esto:

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

Con la esperanza de que las líneas desencadenarían para leer el archivo en su totalidad. Sin suerte. Todavía obtienes una lista vacía.

Cualquier ayuda, sugerencia es muy apreciada.

Respuesta

5

El código ByteString es

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

Pero /proc/whatever no es un archivo real, se genera la demanda, cuando stat ellos para obtener el tamaño del archivo, se obtiene 0. Así ByteString 's readFile lee con éxito 0 bytes.

+1

Ok. Obteniéndose un poco claro ahora. Entonces, ¿cuál es la solución en esta situación? Necesito leer el archivo de estadísticas dentro de un intervalo de 0.5 segundos. La pereza simplemente mata el espectáculo. ¿Tengo que abrir y cerrar el control del archivo de forma explícita? Gracias. –

+0

Creo que tienes que abrir y cerrar explícitamente. Aunque tal vez puedas abrir una vez y mantenerla abierta. De todos modos, creo que 'hGetNonBlocking' es el camino a seguir. 'hGetNonBlocking k' intenta leer' k' bytes, si hay menos disponible, se necesita eso. O 'hGetLine'. –

5

Antes de codificar este tipo de cosas, generalmente es una buena idea verificar si algo ya existe en Hackage. En este caso, encontré el paquete procstat, que parece funcionar muy bien:

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 
+0

Interesante ... Gracias. Ya sabes cómo es cuando aprendes, solo quieres probar y hacer las cosas tú mismo. Debería haber mirado sin embargo. –

Cuestiones relacionadas