我偶然发现了Haskell和FP,并被可能性吓倒了。我内心的老数学书呆子没有任何困难写实际有用的朴素代码。尽管如此,我仍然很难理解如何避免出现一些令人惊讶的性能瓶颈。难以理解的Haskell内存分配行为
所以我写了很简短的代码与天真的实现,然后尝试一些改变,看看性能如何响应。 这里有一个例子,我真的无法理解......我写了这个函数,它找到了一个解决方案Josephus problem,目的与一个天真的列表实现。
m = 3
n = 3000
main = putStr $ "Soldier #" ++ (show $ whosLeft [1..n]) ++ " survived...\n"
whosLeft [lucky] = lucky
whosLeft soldiers = whosLeft $ take (length soldiers -1) $ drop m $ cycle soldiers
后者运行时间为190 ms,根据RTS的生产率为63%。
然后,我想尝试的第一件事是删除(长度士兵-1),并用递减的整数替换它。
运行时间增加到900毫秒,生产力降低到16%,并且使用比以上简单代码多47倍的内存!所以我增加了严格的评估,强制使用Int类型,尝试删除全局变量等,但效果不佳。而我无法理解这种放缓。
m = 3::Int
n = 3000::Int
main = putStr $ "Soldier #" ++ (show $ whosLeft n [1..n]) ++ " survived...\n"
whosLeft 1 [lucky] = lucky
whosLeft n' soldiers = n' `seq` left `seq` whosLeft (n'-1) left
where left = take (n'-1) $ drop m $ cycle soldiers
我已经通过性能相关的文章和帖子筛选过,但我似乎没有得到有关此暗示。仍然是一个Haskell noob我一定会错过一些大的东西...这个如何添加参数(预咀嚼计算...)如此之多地降低速度?
PS:我知道,如果真的约瑟夫曾与3000名士兵,他们就不会需要自杀......
没有必要seq n',whosLeft在n'中已经很严格。但你应该优化编译。 – augustss