Код:
import Network.FastCGI
import Random
import Data.Maybe
import Control.Monad
import Control.Exception as E
handleRequest :: StdGen -> CGI (Int,StdGen)
handleRequest gen = do low <- getInput("low")
high <- getInput("high")
let rnd = randomR (read (fromJust low) :: Int,read (fromJust high) :: Int) gen
liftIO $ (runOneFastCGI . output) (show (fst rnd))
return rnd
main = do gen <- newStdGen
let cgi_handler x = x >>= \(_,gen) -> handleRequest gen
cgi_process x = x >>= \(result,_) -> output (show result)
error_handler x = E.catch x (\err -> (runOneFastCGI . output) ("Error: " ++ show (err :: ErrorCall)))
runFastCGI $ forever $ sequence_ $ iterate cgi_handler (return (1, gen))
Все бы хорошо, но течет оперативка (приблизительно 60мб за 100 000 обращений).
Я изменил код следующим образом:
Код:
import Network.FastCGI
import Random
import Data.Maybe
import Control.Monad
import Control.Exception as E
handleRequest :: StdGen -> CGI (Int,StdGen)
handleRequest gen = do low <- getInput("low")
high <- getInput("high")
let rnd = randomR (read (fromJust low) :: Int,read (fromJust high) :: Int) gen
liftIO $ (runOneFastCGI . output) (show (fst rnd))
return rnd
cgi_handler x = x >>= \(_,gen) -> handleRequest gen
cgi_process x = x >>= \(result,_) -> output (show result)
error_handler x = E.catch x (\err -> (runOneFastCGI . output) ("Error: " ++ show (err :: ErrorCall)))
main = do gen <- newStdGen
-- runFastCGI $ forever $ sequence_ $ iterate cgi_handler (return (1, gen))
runFastCGI $ cgi_process $ last $ take 50000 $ iterate cgi_handler (return (1, gen))
и скормил профайлеру:
Код: Выделить всё
minoru@debian:~/src$ ghc --make -prof -auto-all simplefcgi3.hs
[1 of 1] Compiling Main ( simplefcgi3.hs, simplefcgi3.o )
Linking simplefcgi3 ...Код: Выделить всё
#!/bin/bash
./simplefcgi3 +RTS -pВ результате получил вот такой дамп:
Код:
Fri May 14 11:22 2010 Time and Allocation Profiling Report (Final)
simplefcgi3 +RTS -p -RTS
total time = 0.04 secs (2 ticks @ 20 ms)
total alloc = 5,894,808 bytes (excludes profiling overheads)
COST CENTRE MODULE %time %alloc
main Main 50.0 61.4
cgi_handler Main 50.0 37.3
individual inherited
COST CENTRE MODULE no. entries %time %alloc %time %alloc
MAIN MAIN 1 0 0.0 0.0 100.0 100.0
CAF Main 440 10 0.0 0.0 100.0 98.8
cgi_process Main 448 1 0.0 0.0 0.0 0.0
main Main 446 1 50.0 61.1 100.0 98.8
cgi_handler Main 449 49999 50.0 37.3 50.0 37.7
handleRequest Main 450 1 0.0 0.4 0.0 0.4
CAF Data.Typeable 438 1 0.0 0.0 0.0 0.0
CAF GHC.IO.Exception 432 9 0.0 0.1 0.0 0.1
CAF GHC.Read 417 1 0.0 0.0 0.0 0.0
CAF GHC.Exception 413 3 0.0 0.0 0.0 0.0
CAF Data.Maybe 412 2 0.0 0.0 0.0 0.0
CAF Text.Read.Lex 405 8 0.0 0.0 0.0 0.0
CAF Data.HashTable 379 2 0.0 0.0 0.0 0.0
CAF GHC.IO.Handle.FD 377 2 0.0 0.4 0.0 0.4
CAF System.Posix.Internals 376 1 0.0 0.0 0.0 0.0
CAF GHC.Conc 360 4 0.0 0.0 0.0 0.0
CAF GHC.IO.Handle.Internals 351 1 0.0 0.0 0.0 0.0
CAF GHC.IO.Encoding.Iconv 345 3 0.0 0.0 0.0 0.0
CAF System.Random 338 1 0.0 0.1 0.0 0.1
CAF Data.Fixed 332 2 0.0 0.0 0.0 0.0
CAF Data.Time.Clock.POSIX 330 2 0.0 0.0 0.0 0.0
CAF Data.Time.Clock.CTimeval 329 1 0.0 0.0 0.0 0.0
CAF Network.FastCGI 310 5 0.0 0.0 0.0 0.3
main Main 447 0 0.0 0.3 0.0 0.3
CAF Network.CGI.Protocol 309 7 0.0 0.1 0.0 0.1
CAF Control.Monad.Trans 287 1 0.0 0.0 0.0 0.0
Как видно, течет cgi_handler и main (очевидно, iterate, который его дергает. Как можно избавиться от течи? Использовать какой-нибудь MVar не хотелось бы.