Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance Haskell中的性能改进_Performance_Haskell_Lazy Evaluation - Fatal编程技术网

Performance Haskell中的性能改进

Performance Haskell中的性能改进,performance,haskell,lazy-evaluation,Performance,Haskell,Lazy Evaluation,我想提高haskell编写高性能代码的技能(来自C/C++背景,这对我的自我很重要) 因此,我编写了两个函数,用莱布尼茨公式计算π(这与计算π无关,只是一个示例): CALCPINF通过递归构造一个无限列表。具有foldl的calcPiN和具有n次迭代的lambda 我发现calcpinf比calcPiN快,并且不会因为太大的数字而导致堆栈溢出。 第一个问题:这仅仅是因为懒惰的评估吗 其次,编写了相应的C++程序: using namespace std; double calcPi(int n

我想提高haskell编写高性能代码的技能(来自C/C++背景,这对我的自我很重要)

因此,我编写了两个函数,用莱布尼茨公式计算π(这与计算π无关,只是一个示例):

CALCPINF通过递归构造一个无限列表。具有foldl的calcPiN和具有n次迭代的lambda

我发现calcpinf比calcPiN快,并且不会因为太大的数字而导致堆栈溢出。 第一个问题:这仅仅是因为懒惰的评估吗

其次,编写了相应的C++程序:

using namespace std;
double calcPi(int n){
    double pi = 0;
    for(size_t i = 0; i < n; i++){
        pi += 4.0*(i%2 == 0?1:-1)/(2.0*i + 1.0);
    }
    return pi;
}
int main(){
    std::cout.precision(10);
    cout << calcPi(5000000) << endl;
}
使用名称空间std;
双重计算物价指数(整数n){
双pi=0;
对于(大小i=0;i使用
foldl'
(来自
Data.List
)而不是
foldl
(与延迟生成的列表相比,更喜欢该变体)
  • 使用显式类型签名,否则将得到
    整数
  • 使用优化(
    -O2
  • 以下代码在我的系统上使用~3.599(GHC 8.0.2,无优化)

    使用
    foldl'
    而不是
    foldl
    产生约1.7s(仅为原始时间的约40%)

    使用类型签名可产生0.8s,或减少50%。如果我们现在添加优化,我们最终得到0.06Ss,它仍然是C++变体的两倍(我的机器上有0.033的“代码> -O3,GCC”),但它几乎在那里。 请注意,我们也可以立即使用

    -O2
    来降低一秒钟,但在添加
    -O2
    之前的任何改进(但不一定!)也会导致之后的改进

    这里所有的时间都取决于是否使用了类型签名、
    foldl'
    或优化标志。请注意,类型签名与
    -O2
    一起已经使我们接近C++的速度。但是,这种行为通常不成立,我们需要根据懒散程度更改一些函数:

    类型注解
    foldl'
    -O2
    运行时[s] 对 不 对 0.063 对 对 对 0.063 不 对 对 0.180 不 不 对 0.190 对 对 不 0.825 不 对 不 1.700 对 不 不 2.477 不 不 不 3.599
    如果你对评论感兴趣,那么可能更适合你的问题。基准测试很难。你实际上是如何计算这些时间的?这一点并不明显,因为你的两个定义甚至没有做相同的事情:一个是列表,另一个是从一个数字到另一个数字的函数。至少很容易说懒惰是一种可能e问题:
    foldl
    从来都不是一个好主意,
    foldl'
    将是一个改进。硬件平台、编译器、编译器版本、优化级别?您是否尝试过foldl'和foldr?一般建议:1)提供特定类型的注释,例如
    :Double
    ,2)永远不要使用
    foldl
    ,使用
    foldl'计算数值时,3)避免GHCi,用GHC和<代码> -O2编译。这里增加5000000个图似乎使间隙更明显。GHC在500000000的机器上运行6X次。我没有想到。@ CG 6X倍与C++变体相比,GHC优化代码和G++COD之间仍然有因子2。e> -O3
    ,即使有500000000。@chi-Huh.也无法重现这种差距。我得到了~2.272s(g++-O3)和~4.972s(GHC-O2),所以速度要慢2.4倍。但是,我的GCC和GHC不是最新的。我会查看一下配置文件。@Zeta我的老式g++-O3 7.5.0似乎比你的快得多。我的GHC-O2 8.6.5更符合你的数字。我们两人都没有真正使用最新的编译器。在我的机器上,使用
    -fllvm
    可以加快速度,大约6使用
    -fllvm
    时x的速度与不使用
    -fllvm时一样快。(根据经验,繁重的数值计算通常受益于
    -fllvm
    using namespace std;
    double calcPi(int n){
        double pi = 0;
        for(size_t i = 0; i < n; i++){
            pi += 4.0*(i%2 == 0?1:-1)/(2.0*i + 1.0);
        }
        return pi;
    }
    int main(){
        std::cout.precision(10);
        cout << calcPi(5000000) << endl;
    }
    
    calcPiStep k = (if even k then 4.0 else -4.0) / (2.0*fromIntegral k + 1.0)
    calcPiN n = foldl (\p x -> p + calcPiStep x) 0.0 [0..n]
    
    main = print $ calcPiN 5000000
    
    import Data.List
    calcPiStep k = (if even k then 4.0 else -4.0) / (2.0*fromIntegral k + 1.0)
    calcPiN n = foldl' (\p x -> p + calcPiStep x) 0.0 [0..n]
    
    main = print $ calcPiN 5000000