for循环性能怪胎在.NET 64位:偶数迭代的亲和力? [英] for-loop performance oddity in .NET x64: even-number-iteration affinity?

查看:189
本文介绍了for循环性能怪胎在.NET 64位:偶数迭代的亲和力?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有关循环具有大量迭代运行一空,我得到它需要运行多长时间完全不同的数字:

Running an empty for-loop with large numbers of iterations, I'm getting wildly different numbers in how long it takes to run:

public static class Program
{
    static void Main()
    {
        var sw = new Stopwatch();
        sw.Start();
        for (var i = 0; i < 1000000000; ++i)
        {
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);
    }
}

以上将运行在200毫秒左右我的机器上,但如果我增加它1000000001,那么它需要的 4X 作为长!然后,如果我让1000000002,那么它的下到200毫秒一次!

The above will run in around 200ms on my machine, but if I increase it to 1000000001, then it takes 4x as long! Then if I make it 1000000002, then it's down to 200ms again!

本的似乎的发生为偶数迭代。如果我去的(VAR I = 1; I&LT; 1000000001 ,(注意从1开始,而不是0),则是200毫秒或者,如果我这样做 I&LT; = 1000000001 (注意不到的或等于的),那么它的200ms或(VAR I = 0; I&LT; 20亿,我+ = 2)

This seems to happen for an even number of iterations. If I go for (var i = 1; i < 1000000001, (note starting at 1 instead of 0) then it's 200ms. Or if I do i <= 1000000001 (note less than or equal) then it's 200ms. Or (var i = 0; i < 2000000000; i += 2) as well.

这只是似乎是在x64,但在所有的.NET版本最多(至少)4.0。此外,它只有在出现在释放模式与调试器分离。

This appears only to be on x64, but on all .NET versions up to (at least) 4.0. Also it appears only when in release mode with debugger detached.

更新我在想,这可能是由于一些聪明位移入的JIT,但以下似乎反驳说:如果你做一些像创建一个对象,这个循环里面,那么的大约4倍,只要过:

UPDATE I was thinking that this was likely due to some clever bit shifting in the jit, but the following seems to disprove that: if you do something like create an object inside that loop, then that takes about 4x as long too:

public static class Program
{
    static void Main()
    {
        var sw = new Stopwatch();
        sw.Start();
        object o = null;
        for (var i = 0; i < 1000000000; i++)
        {
            o = new object();
        }
        sw.Stop();
        Console.WriteLine(o); // use o so the compiler won't optimize it out
        Console.WriteLine(sw.ElapsedMilliseconds);
    }
}

这需要我的机器上1秒左右,但后来增加1到1000000001它需要的4秒的。这是一个额外的3000ms,因此它无法真正是由于位移,因为这显示了在原有的问题太多一个3000ms的差异。

This takes around 1 second on my machine, but then increasing by 1 to 1000000001 it takes 4 seconds. That's an extra 3000ms, so it couldn't really be due to bit shifting, as that would have shown up as a 3000ms difference in the original problem too.

推荐答案

那么这里有反汇编:

00000031  xor         eax,eax 
  for (var i = 0; i < 1000000001; ++i)
00000033  inc         eax           
00000035  cmp         eax,3B9ACA01h 
0000003a  jl          0000000000000033 
0000003c  movzx       eax,byte ptr [rbx+18h] 
00000040  test        eax,eax 
00000042  je          0000000000000073 

00000031  xor         eax,eax 
     for (var i = 0; i < 1000000000; ++i)
00000033  add         eax,4 
00000036  cmp         eax,3B9ACA00h 
0000003b  jl          0000000000000033 
0000003d  movzx       eax,byte ptr [rbx+18h] 
00000041  test        eax,eax 
00000043  je          0000000000000074 

我看到的唯一的区别是,在偶数循环中,循环索引加4在时间(添加eax中4 )代替1-一次( INC EAX ),所以它完成,因为环路4倍快。

The only difference I see is that in the even loop, the loop index is incremented by 4 at a time (add eax 4) instead of 1 at a time (inc eax) so it finishes the loop 4x faster because of that.

这只是猜测,但我相信这是展开以4倍的循环。因此,它把身体内循环4次,只是增量快4倍。但因为身体是空的,空体倍4仍然是空的,你获得更大的收益比你会期望从循环展开。

This is just speculation but I believe it is unrolling the loop by a factor of 4. So it places the body 4 times inside the loop and just increments 4 times faster. But because the body is empty, empty body times 4 is still empty, you gain much bigger gain than you would expect from loop unrolling.

这篇关于for循环性能怪胎在.NET 64位:偶数迭代的亲和力?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆