gpt4 book ai didi

haskell - 有哪些可能的 Haskell 优化键?

转载 作者:行者123 更新时间:2023-12-04 16:25:51 25 4
gpt4 key购买 nike

我找到了用不同语言解决非常简单的任务的基准 https://github.com/starius/lang-bench .这是 Haskell 的代码:

cmpsum i j k =
if i + j == k then 1 else 0

main = print (sum([cmpsum i j k |
i <- [1..1000], j <- [1..1000], k <- [1..1000]]))

正如您在基准测试中看到的那样,此代码运行速度非常慢,我发现这很奇怪。
我试图内联函数 cmpsum 并使用下一个标志进行编译:
ghc -c -O2 main.hs

但它真的没有帮助。我不是在问优化算法,因为它对所有语言都是一样的,而是关于可能的编译器或代码优化,可以使这个代码运行得更快。

最佳答案

不是一个完整的答案,对不起。在我的机器上使用 GHC 7.10 进行编译,我的版本大约为 12 秒。

我建议始终使用 -Wall 进行编译这表明我们的数字默认为无限精度 Integer类型。修复:

module Main where

cmpsum :: Int -> Int -> Int -> Int
cmpsum i j k =
if i + j == k then 1 else 0

main :: IO ()
main = print (sum([cmpsum i j k |
i <- [1..1000], j <- [1..1000], k <- [1..1000]]))

这对我来说大约需要 5 秒。与 +RTS -s 一起运行似乎表明我们在常量内存中有一个循环:
          87,180 bytes allocated in the heap
1,704 bytes copied during GC
42,580 bytes maximum residency (1 sample(s))
18,860 bytes maximum slop
1 MB total memory in use (0 MB lost due to fragmentation)

Tot time (elapsed) Avg pause Max pause
Gen 0 0 colls, 0 par 0.000s 0.000s 0.0000s 0.0000s
Gen 1 1 colls, 0 par 0.000s 0.000s 0.0001s 0.0001s

INIT time 0.000s ( 0.001s elapsed)
MUT time 4.920s ( 4.919s elapsed)
GC time 0.000s ( 0.000s elapsed)
EXIT time 0.000s ( 0.000s elapsed)
Total time 4.920s ( 4.921s elapsed)

%GC time 0.0% (0.0% elapsed)

Alloc rate 17,719 bytes per MUT second

Productivity 100.0% of total user, 100.0% of total elapsed
-fllvm再刮一秒左右。也许其他人可以进一步研究它。

编辑 : 稍微深入一点。看起来融合并没有发生。就算我换了 sumfoldr (+) 0这是一个明确的 "good producer/good consumer"一对。
Rec {
$wgo [InlPrag=[0], Occ=LoopBreaker] :: Int# -> Int#
[GblId, Arity=1, Str=DmdType <S,U>]
$wgo =
\ (w :: Int#) ->
let {
$j :: Int# -> Int#
[LclId, Arity=1, Str=DmdType]
$j =
\ (ww [OS=OneShot] :: Int#) ->
letrec {
$wgo1 [InlPrag=[0], Occ=LoopBreaker] :: [Int] -> Int#
[LclId, Arity=1, Str=DmdType <S,1*U>]
$wgo1 =
\ (w1 :: [Int]) ->
case w1 of _ [Occ=Dead] {
[] -> ww;
: y ys ->
case $wgo1 ys of ww1 { __DEFAULT ->
case lvl of _ [Occ=Dead] {
[] -> ww1;
: y1 ys1 ->
case y of _ [Occ=Dead] { I# y2 ->
case y1 of _ [Occ=Dead] { I# y3 ->
case tagToEnum# @ Bool (==# (+# w y2) y3) of _ [Occ=Dead] {
False ->
letrec {
$wgo2 [InlPrag=[0], Occ=LoopBreaker] :: [Int] -> Int#
[LclId, Arity=1, Str=DmdType <S,1*U>]
$wgo2 =
\ (w2 :: [Int]) ->
case w2 of _ [Occ=Dead] {
[] -> ww1;
: y4 ys2 ->
case y4 of _ [Occ=Dead] { I# y5 ->
case tagToEnum# @ Bool (==# (+# w y2) y5) of _ [Occ=Dead] {
False -> $wgo2 ys2;
True -> case $wgo2 ys2 of ww2 { __DEFAULT -> +# 1 ww2 }
}
}
}; } in
$wgo2 ys1;
True ->
letrec {
$wgo2 [InlPrag=[0], Occ=LoopBreaker] :: [Int] -> Int#
[LclId, Arity=1, Str=DmdType <S,1*U>]
$wgo2 =
\ (w2 :: [Int]) ->
case w2 of _ [Occ=Dead] {
[] -> ww1;
: y4 ys2 ->
case y4 of _ [Occ=Dead] { I# y5 ->
case tagToEnum# @ Bool (==# (+# w y2) y5) of _ [Occ=Dead] {
False -> $wgo2 ys2;
True -> case $wgo2 ys2 of ww2 { __DEFAULT -> +# 1 ww2 }
}
}
}; } in
case $wgo2 ys1 of ww2 { __DEFAULT -> +# 1 ww2 }
}
}
}
}
}
}; } in
$wgo1 lvl } in
case w of wild {
__DEFAULT -> case $wgo (+# wild 1) of ww { __DEFAULT -> $j ww };
1000 -> $j 0
}
end Rec }

事实上,看核心为 print $ foldr (+) (0:: Int) $ [ i+j | i <- [0..10000], j <- [0..10000]]似乎只融合了列表理解的第一层。那是一个错误吗?

关于haskell - 有哪些可能的 Haskell 优化键?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28177383/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com