Haskell 如何优化生成大型IntMap?
下面代码的Haskell 如何优化生成大型IntMap?,haskell,Haskell,下面代码的allCases大小为2^20IntMap,其生成需要大量计算和内存。我不知道这是否是不可避免的成本,我怎样才能找出造成低效率的地方 import Control.Monad (forM_) import Control.Monad.ST import Data.Array import Data.Array.ST import Data.Bits import Data.List import qualified Data.IntMap as M type Switch = Int
allCases
大小为2^20IntMap
,其生成需要大量计算和内存。我不知道这是否是不可避免的成本,我怎样才能找出造成低效率的地方
import Control.Monad (forM_)
import Control.Monad.ST
import Data.Array
import Data.Array.ST
import Data.Bits
import Data.List
import qualified Data.IntMap as M
type Switch = Int
type Clock = Int
switches :: Array Switch [Clock]
switches = listArray (0, 9) [
[0, 1, 2],
[3, 7, 9, 11],
[4, 10, 14, 15],
[0, 4, 5, 6, 7],
[6, 7, 8, 10, 12],
[0, 2, 14, 15],
[3, 14, 15],
[4, 5, 7, 1, 15],
[1, 2, 3, 4, 5],
[3, 4, 5, 9, 13]]
type Quads = Int
intsToQuads :: [Int] -> Quads
intsToQuads [] = 0
intsToQuads (x:xs) = x .|. (intsToQuads xs `shiftL` 2)
switchCases :: [[Int]]
switchCases = sequence $ replicate 10 [0..3]
applySwitch :: Int -> STUArray s Int Int -> ST s ()
applySwitch sw clocks = forM_ (switches ! sw) $ \ix -> do
clock <- readArray clocks ix
writeArray clocks ix ((clock + 1) `rem` 4)
allCasesST :: Int -> STUArray s Int Int -> Int -> ST s (M.IntMap Int)
allCasesST ix clocks pushs
| ix > 9 = do
cs <- getElems clocks
return (M.singleton (intsToQuads cs) pushs)
| otherwise = do
rs <- mapM next [pushs..pushs + 3]
return (M.unions rs)
where
next pu = do
rs <- allCasesST (ix + 1) clocks pu
applySwitch ix clocks
return rs
allCases :: M.IntMap Int
allCases = runST $ do
st <- newArray (0,15) 0
allCasesST 0 st 0
main = do
putStrLn . show $ M.lookup 0 allCases
return ()
.prof文件(为保持整洁进行了一些修改)
2017年12月25日星期一23:52时间和分配分析报告(最终版)
a、 exe+RTS-p-hc-xc-s-c-RTS
总时间=1.52秒(1000 us时1518个滴答声,1个处理器)
总alloc=1576087408字节(不包括分析开销)
成本中心模块SRC%时间%alloc
intsToQuads Main.hs:38:29-42 24.9 17.0
AllcaseSt Main.hs:55:13-23 13.7 20.2
applySwitch Main.hs:44:25-45 12.20.0
AllcaseSt Main.hs:51:11-25 10.5 44.2
applySwitch Main.hs:46:3-44 9.50.0
intsToQuads Main.hs:38:22-54 7.20.0
AllcaseSt.next Main.hs:58:13-41 6.2 5.7
intsToQuads Main.hs:38:29-53 4.20.0
applySwitch Main.hs:45:12-30 2.6 7.1
AllcaseSt.next Main.hs:59:7-27 2.2 0.0
AllcaseSt Main.hs:52:26-39 1.8 1.1
ApplySwitchMain.hs:(44,25)-(46,44)1.50.0
AllcaseSt Main.hs:52:13-46 1.4 2.7
AllcaseSt Main.hs:54:11-38 0.7 2.1
个人继承
成本中心SRC分录%time%alloc%time%alloc
主要0.1 0.0 100.0 100.0
CAF GHC.IO.Encoding.CodePage 0.0.0.0 0.0
CAF GHC.IO.Encoding 0.0 0.0.0 0.0
CAF GHC.IO.Handle.Text 0.0.0.0 0.0
CAF GHC.显示0.0.0.0.0
CAF GHC.IO.Handle.FD 0.0.0.0.0
CAF 0.0 0.0 99.9 100.0
所有主要病例。hs:(63,12)-(65,19)0.0 0.0 99.9 100.0
allCases Main.hs:64:9-25 0.0.0.0
AllcaseStST Main.hs:55:5-24 0 0.0 0.0 5.5 5.3
AllcaseSt Main.hs:55:13-23 0 5.5 5.3 5.5 5.3
AllcaseSt Main.hs:54:11-38 0.7 2.1 94.5 94.7
AllcaseSt.next Main.hs:59:7-27 0 0.1 0.0 0.5 0.0
applyswitchmain.hs:(44,25)-(46,44)0.0.0.30.0
applySwitch Main.hs:44:25-45 0.1 0.0 0.3 0.0
applySwitch Main.hs:45:12-30 0.0.0.0
applySwitch Main.hs:44:32-44 0.20.0 0.20.0
AllcaseSt.next Main.hs:58:13-41 06.2 5.7 93.3 92.5
AllcaseSt Main.hs:52:5-47 0.1 0.0 39.7 20.8
AllcaseSt Main.hs:52:13-46 0 1.4 2.7 39.6 20.8
AllcaseSt Main.hs:52:26-39 01.81.138.218.1
intsToQuads Main.hs:38:22-54 0 7.2 0.0 36.4 17.0
intsToQuads Main.hs:38:29-53 0 4.2 0.0 29.1 17.0
intsToQuads Main.hs:38:29-42 0 24.9 17.0 24.9 17.0
AllcaseSt Main.hs:55:5-24 0 0.1 0.0 8.3 14.9
AllcaseSt Main.hs:55:13-23 0 8.214.9 8.214.9
AllcaseSt Main.hs:51:11-25 0 10.5 44.2 10.5 44.2
AllcaseSt.next Main.hs:59:7-27 0 2.1 0.0 28.7 7.1
applyswitchmain.hs:(44,25)-(46,44)01.50.026.57.1
applySwitch Main.hs:44:25-45 0 12.1 0.0 25.0 7.1
applySwitch Main.hs:46:3-44 0 9.5 0.0 10.4 0.0
applySwitch Main.hs:46:25-43 0.9 0.0 0.9 0.0
applySwitch Main.hs:45:12-30 0 2.6 7.1 2.6 7.1
main main.hs:68:3-390.0.0.0
main main.hs:68:21-39 0.0.0.0
main main.hs:68:3-17 0.0.0.0
主开关.hs:(22,12)-(32,19)0.0.0.0
main main.hs:68:3-390.0.0.0
main main.hs:68:3-17 0.0.0.0
您的算法有点太懒了,您正在地图中放置未评估的Thunk
您的原始代码执行如下操作:
<<ghc: 1185249008 bytes, 1136 GCs, 85006914/288126544 avg/max bytes residency (10 samples), 827M in use, 0.000 INIT (0.002 elapsed), 0.595 MUT (0.605 elapsed), 1.830 GC (2.065 elapsed) :ghc>>
./jeiea +RTS -tstderr 2.43s user 0.32s system 99% cpu 2.773 total
这是72MB的驻留空间,大约1秒,但差异很大
编辑:
完整的代码并运行:
import Control.Monad (forM_)
import Control.Monad.ST
import Data.Array
import Data.Array.ST
import Data.Bits
import Data.List
import qualified Data.IntMap as M
type Switch = Int
type Clock = Int
switches :: Array Switch [Clock]
switches = listArray (0, 9) [
[0, 1, 2],
[3, 7, 9, 11],
[4, 10, 14, 15],
[0, 4, 5, 6, 7],
[6, 7, 8, 10, 12],
[0, 2, 14, 15],
[3, 14, 15],
[4, 5, 7, 1, 15],
[1, 2, 3, 4, 5],
[3, 4, 5, 9, 13]]
type Quads = Int
intsToQuads :: [Int] -> Quads
intsToQuads [] = 0
intsToQuads (x:xs) = x .|. (intsToQuads xs `shiftL` 2)
switchCases :: [[Int]]
switchCases = sequence $ replicate 10 [0..3]
applySwitch :: Int -> STUArray s Int Int -> ST s ()
applySwitch sw clocks = forM_ (switches ! sw) $ \ix -> do
clock <- readArray clocks ix
let n = ((clock + 1) `rem` 4)
n `seq` writeArray clocks ix n
allCasesST :: Int -> STUArray s Int Int -> Int -> ST s (M.IntMap Int)
allCasesST ix clocks pushs
| ix > 9 = do
cs <- getElems clocks
let n = intsToQuads cs
n `seq` return (M.singleton n pushs)
| otherwise = do
rs <- mapM next [pushs..pushs + 3]
return (M.unions rs)
where
next pu = do
let n = ix + 1
rs <- n `seq` allCasesST n clocks pu
applySwitch ix clocks
return rs
allCases :: M.IntMap Int
allCases = runST $ do
st <- newArray (0,15) 0
allCasesST 0 st 0
main = do
putStrLn . show $ M.lookup 0 allCases
return ()
import-Control.Monad(表单)
进口管制站
导入数据。数组
导入Data.Array.ST
导入数据
导入数据。列表
将限定的Data.IntMap作为M导入
类型开关=Int
类型时钟=Int
开关::阵列开关[时钟]
开关=listArray(0,9)[
[0, 1, 2],
[3, 7, 9, 11],
[4, 10, 14, 15],
[0, 4, 5, 6, 7],
[6, 7, 8, 10, 12],
[0, 2, 14, 15],
[3, 14, 15],
[4, 5, 7, 1, 15],
[1, 2, 3, 4, 5],
[3, 4, 5, 9, 13]]
类型Quads=Int
intsToQuads::[Int]->Quads
intsToQuads[]=0
intsToQuads(x:xs)=x.|。(intsToQuads xs`shiftL`2)
开关箱::[[Int]]
switchCases=序列$replicate 10[0..3]
applySwitch::Int->stus数组Int->ST
<<ghc: 1185249008 bytes, 1136 GCs, 85006914/288126544 avg/max bytes residency (10 samples), 827M in use, 0.000 INIT (0.002 elapsed), 0.595 MUT (0.605 elapsed), 1.830 GC (2.065 elapsed) :ghc>>
./jeiea +RTS -tstderr 2.43s user 0.32s system 99% cpu 2.773 total
allCasesST :: Int -> STUArray s Int Int -> Int -> ST s (M.IntMap Int)
allCasesST ix clocks pushs
| ix > 9 = do
cs <- getElems clocks
let n = intsToQuads cs
n `seq` return (M.singleton n pushs)
<<ghc: 1151694576 bytes, 1104 GCs, 26972457/72834536 avg/max bytes residency (11 samples), 215M in use, 0.000 INIT (0.002 elapsed), 0.500 MUT (0.515 elapsed), 0.735 GC (0.816 elapsed) :ghc>>
./jeiea +RTS -tstderr 1.24s user 0.11s system 98% cpu 1.367 total
<<ghc: 1151694576 bytes, 1104 GCs, 26972457/72834536 avg/max bytes residency (11 samples), 215M in use, 0.000 INIT (0.002 elapsed), 0.389 MUT (0.395 elapsed), 0.517 GC (0.573 elapsed) :ghc>>
import Control.Monad (forM_)
import Control.Monad.ST
import Data.Array
import Data.Array.ST
import Data.Bits
import Data.List
import qualified Data.IntMap as M
type Switch = Int
type Clock = Int
switches :: Array Switch [Clock]
switches = listArray (0, 9) [
[0, 1, 2],
[3, 7, 9, 11],
[4, 10, 14, 15],
[0, 4, 5, 6, 7],
[6, 7, 8, 10, 12],
[0, 2, 14, 15],
[3, 14, 15],
[4, 5, 7, 1, 15],
[1, 2, 3, 4, 5],
[3, 4, 5, 9, 13]]
type Quads = Int
intsToQuads :: [Int] -> Quads
intsToQuads [] = 0
intsToQuads (x:xs) = x .|. (intsToQuads xs `shiftL` 2)
switchCases :: [[Int]]
switchCases = sequence $ replicate 10 [0..3]
applySwitch :: Int -> STUArray s Int Int -> ST s ()
applySwitch sw clocks = forM_ (switches ! sw) $ \ix -> do
clock <- readArray clocks ix
let n = ((clock + 1) `rem` 4)
n `seq` writeArray clocks ix n
allCasesST :: Int -> STUArray s Int Int -> Int -> ST s (M.IntMap Int)
allCasesST ix clocks pushs
| ix > 9 = do
cs <- getElems clocks
let n = intsToQuads cs
n `seq` return (M.singleton n pushs)
| otherwise = do
rs <- mapM next [pushs..pushs + 3]
return (M.unions rs)
where
next pu = do
let n = ix + 1
rs <- n `seq` allCasesST n clocks pu
applySwitch ix clocks
return rs
allCases :: M.IntMap Int
allCases = runST $ do
st <- newArray (0,15) 0
allCasesST 0 st 0
main = do
putStrLn . show $ M.lookup 0 allCases
return ()
% time ./jeiea +RTS -tstderr
Just 0
<<ghc: 1151694576 bytes, 1104 GCs, 26972457/72834536 avg/max bytes residency (11 samples), 215M in use, 0.000 INIT (0.005 elapsed), 0.812 MUT (0.820 elapsed), 0.979 GC (1.093 elapsed) :ghc>>
./jeiea +RTS -tstderr 1.79s user 0.16s system 99% cpu 1.971 total