猿问

简单 C# 程序的惊人不同性能

下面是一个简单的程序,只需稍作改动,就会对性能产生重大影响,我不明白为什么。


该程序所做的并不真正相关,但它通过计算两个不同质量的物体与墙壁之间的碰撞以非常复杂的方式计算 PI。当我改变代码时,我注意到性能上有很大的差异。


有问题的行是数学上等价的注释行。使用慢速版本使整个程序花费的时间大约是使用快速版本的两倍。


int iterations = 0;


for (int i = 4; i < 9; i++)

{

    Stopwatch s = Stopwatch.StartNew();


    double ms = 1.0;

    double mL = Math.Pow(100.0, i);

    double uL = 1.0;

    double us = 0.0;

    double msmLInv = 1d / (ms + mL);


    long collisions = 0;

    while (!(uL < 0 && us <= 0 && uL <= us))

    {

        Debug.Assert(++iterations > 0);

        ++collisions;


        double vs = (2 * mL * uL + us * (ms - mL)) * msmLInv;


        //double vL = (2 * ms * us - uL * (ms - mL)) * msmLInv; //fast

        double vL = uL + (us - vs) / mL; //slow



        Debug.Assert(Math.Abs(((2 * ms * us - uL * (ms - mL)) * msmLInv) - (uL + (us - vs) / mL)) < 0.001d); //checks equality between fast and slow

        if (vs > 0)

        {

            ++collisions;

            vs = -vs;

        }


        us = vs;

        uL = vL;

    }


    s.Stop();



    Debug.Assert(collisions.ToString() == "314159265359".Substring(0, i + 1)); //check the correctness

    Console.WriteLine($"i: {i}, T: {s.ElapsedMilliseconds / 1000f}, PI: {collisions}");

}


Debug.Assert(iterations == 174531180); //check that we dont skip loops


Console.Write("Waiting...");

Console.ReadKey();

我的直觉说,因为快速版本有 7 个操作,而慢版本有 4 个操作,所以慢版本应该更快,但事实并非如此。


我使用 .NET Reflector 对程序进行了反汇编,结果显示它们大部分是相同的,正如预期的那样,除了下面显示的部分。前后的代码相同


//slow

ldloc.s uL

ldloc.2 

ldloc.s us

ldloc.s vs

sub 

mul 

ldloc.3 

div 

add 


侃侃尔雅
浏览 94回答 2
2回答

犯罪嫌疑人X

我认为原因是 CPU指令流水线。你的慢方程取决于vs,这意味着vs必须先计算,然后vl计算。但是在您的快速方程式中,可以将更多指令流水线化vs并且vl可以同时计算,因为它们不相互依赖。请不要将此与多线程混淆。指令流水线是在非常低的硬件级别实现的东西,它试图同时利用尽可能多的 CPU 模块来实现最大的指令吞吐量。

跃然一笑

你的计算不相等double vL = (2 * ms * us - uL * (ms - mL)) / (ms + mL); //fastdouble vL = uL + ms * (us - vs) / mL; //slow示例:我错过vs了快速版本我希望您的 while 循环因此进行更多迭代?
随时随地看视频慕课网APP
我要回答