Refabricarlo ligeramente (básicamente un pliegue a la izquierda) proporciona un rendimiento mucho mejor y reduce la sobrecarga de GC bastante al analizar un archivo de 8388600 bytes.
{-# LANGUAGE BangPatterns #-}
module Main (main) where
import qualified Data.ByteString.Lazy as BL
import Data.Binary.Get
data Trade = Trade
{ timestamp :: {-# UNPACK #-} !Int
, price :: {-# UNPACK #-} !Int
, qty :: {-# UNPACK #-} !Int
} deriving (Show)
getTrade :: Get Trade
getTrade = do
timestamp <- getWord32le
price <- getWord32le
qty <- getWord16le
return $! Trade (fromIntegral timestamp) (fromIntegral price) (fromIntegral qty)
countTrades :: BL.ByteString -> Int
countTrades input = stepper (0, input) where
stepper (!count, !buffer)
| BL.null buffer = count
| otherwise =
let (trade, rest, _) = runGetState getTrade buffer 0
in stepper (count+1, rest)
main :: IO()
main = do
input <- BL.readFile "trades.bin"
let trades = countTrades input
print trades
Y las estadísticas de tiempo de ejecución relacionadas. Aunque los números de asignación son similares, el GC y el tamaño máximo de almacenamiento dinámico son bastante diferentes entre las revisiones.
Todos los ejemplos aquí fueron construidos con GHC 7.4.1-O2.
La fuente original, correr con + RTS -K1G -RTS debido al excesivo uso de espacio de pila:
426,003,680 bytes allocated in the heap
443,141,672 bytes copied during GC
99,305,920 bytes maximum residency (9 sample(s))
203 MB total memory in use (0 MB lost due to fragmentation)
Total time 0.62s ( 0.81s elapsed)
%GC time 83.3% (86.4% elapsed)
revisión de Daniel:
357,851,536 bytes allocated in the heap
220,009,088 bytes copied during GC
40,846,168 bytes maximum residency (8 sample(s))
85 MB total memory in use (0 MB lost due to fragmentation)
Total time 0.24s ( 0.28s elapsed)
%GC time 69.1% (71.4% elapsed)
Y este post:
290,725,952 bytes allocated in the heap
109,592 bytes copied during GC
78,704 bytes maximum residency (10 sample(s))
2 MB total memory in use (0 MB lost due to fragmentation)
Total time 0.06s ( 0.07s elapsed)
%GC time 5.0% (6.0% elapsed)
hay un capítulo en el mundo real sobre el perfilado, y unas pocas preguntas etiquetadas [haskell] + [rendimiento] en so.com - tal vez esto es de ayuda para ti tú – epsilonhalbe
@epsilonhalbe Gracias, tuve una buena búsqueda y este patrón es el que está en los documentos para Data.Binary.Get. Sospecho que se trata de un problema de "recursión casi recurrente", pero me queda un poco difícil de descifrar. –
Esto es complicado ya que Data.Binary.Get parece estricto. Hice un comentario anterior sobre tratar de obtener una mejor pereza, pero la he eliminado porque no era aplicable. La respuesta de Daniel Fischer le muestra cómo hacer un mejor trabajo de ser estricto. –