在這種情況下,為什么.NET比C ++更快? - Why is .NET faster than C++ in this case? -开发者知识库

在這種情況下,為什么.NET比C ++更快? - Why is .NET faster than C++ in this case? -开发者知识库,第1张

Make sure you run outside of the IDE. That is key.

確保您在IDE外部運行。這是關鍵。

-edit- I LOVE SLaks comment. "The amount of misinformation in these answers is staggering." :D

-edit-我喜歡SLaks評論。 “這些答案中的錯誤信息量是驚人的。” :d

Calm down guys. Pretty much all of you were wrong. I DID make optimizations. It turns out whatever optimizations I made wasn't good enough. I ran the code in GCC using gettimeofday (I'll paste code below) and used g -O2 file.cpp and got slightly faster results then C#. Maybe MS didn't create the optimizations needed in this specific case but after downloading and installing mingw I was tested and found the speed to be near identical. Justicle Seems to be right. I could have sworn I use clock on my PC and used that to count and found it was slower but problem solved. C speed isn't almost twice as slower in the MS compiler.

冷靜下來。幾乎所有人都錯了。我做了優化。事實證明,我所做的任何優化都不夠好。我使用gettimeofday在GCC中運行代碼(我將在下面粘貼代碼)並使用g -O2 file.cpp並獲得比C#略快的結果。也許MS沒有創建在這個特定情況下所需的優化,但在下載和安裝mingw后,我進行了測試,發現速度幾乎相同。 Justicle似乎是對的。我可以發誓我在我的電腦上使用時鍾並使用它來計算並發現它速度較慢但問題已解決。在MS編譯器中,C 速度幾乎不會慢兩倍。

When my friend informed me of this I couldn't believe it. So I took his code and put some timers onto it.

當我的朋友告訴我這件事時我無法相信。所以我拿了他的代碼並把一些定時器放在上面。

Instead of Boo I used C#. I constantly got faster results in C#. Why? The .NET version was nearly half the time no matter what number I used.

而不是Boo,我使用了C#。我不斷在C#中獲得更快的結果。為什么?無論我使用什么數字,.NET版本幾乎都有一半的時間。

C version (bad version):

C 版(壞版):

#include <iostream>
#include <stdio.h>
#include <intrin.h>
#include <windows.h>
using namespace std;

int fib(int n)
{
    if (n < 2) return n;
    return fib(n - 1)   fib(n - 2);
}

int main()
{
    __int64 time = 0xFFFFFFFF;
    while (1)
    {
        int n;
        //cin >> n;
        n = 41;
        if (n < 0) break;
__int64 start = __rdtsc();
        int res = fib(n);
__int64 end = __rdtsc();
        cout << res << endl;
        cout << (float)(end-start)/1000000<<endl;
        break;
    }

    return 0;
}

C version (better version):

C 版本(更好的版本):

#include <iostream>
#include <stdio.h>
#include <intrin.h>
#include <windows.h>
using namespace std;

int fib(int n)
{
    if (n < 2) return n;
    return fib(n - 1)   fib(n - 2);
}

int main()
{
    __int64 time = 0xFFFFFFFF;
    while (1)
    {
        int n;
        //cin >> n;
        n = 41;
        if (n < 0) break;
        LARGE_INTEGER start, end, delta, freq;
        ::QueryPerformanceFrequency( &freq );
        ::QueryPerformanceCounter( &start );
        int res = fib(n);
        ::QueryPerformanceCounter( &end );
        delta.QuadPart = end.QuadPart - start.QuadPart;
        cout << res << endl;
        cout << ( delta.QuadPart * 1000 ) / freq.QuadPart <<endl;
break;
    }

    return 0;
}

C# version:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Threading;
using System.IO;

using System.Diagnostics;

namespace fibCSTest
{
    class Program
    {
         static int fib(int n)
         {
            if (n < 2)return n;
            return fib(n - 1)   fib(n - 2);
         }

         static void Main(string[] args)
         {
             //var sw = new Stopwatch();
             //var timer = new PAB.HiPerfTimer();
             var timer = new Stopwatch();
             while (true)
             {
                 int n;
                 //cin >> n;
                 n = 41;
                 if (n < 0) break;
                 timer.Start();
                 int res = fib(n);
                 timer.Stop();
                 Console.WriteLine(res);
                 Console.WriteLine(timer.ElapsedMilliseconds);
                 break;
             }
         }
    }
}

GCC version:

#include <iostream>
#include <stdio.h>
#include <sys/time.h>
using namespace std;

int fib(int n)
{
    if (n < 2) return n;
    return fib(n - 1)   fib(n - 2);
}

int main()
{
    timeval start, end;
    while (1)
    {
        int n;
        //cin >> n;
        n = 41;
        if (n < 0) break;
        gettimeofday(&start, 0);
        int res = fib(n);
        gettimeofday(&end, 0);
        int sec = end.tv_sec - start.tv_sec;
        int usec = end.tv_usec - start.tv_usec;
        cout << res << endl;
        cout << sec << " " << usec <<endl;
        break;
    }

    return 0;
}

13 个解决方案

#1


16  

EDIT: TL/DR version: CLR JIT will inline one level of recursion, MSVC 8 SP1 will not without #pragma inline_recursion(on). And you should run the C# version outside of a debugger to get the fully optimized JIT.

編輯:TL / DR版本:CLR JIT將內聯一級遞歸,MSVC 8 SP1將不會沒有#pragma inline_recursion(on)。您應該在調試器之外運行C#版本以獲得完全優化的JIT。

I got similar results to acidzombie24 with C# vs. C using VS 2008 SP1 on a Core2 Duo laptop running Vista plugged in with "high performance" power settings (~1600 ms vs. ~3800 ms). It's kind of tricky to see the optimized JIT'd C# code, but for x86 it boils down to this:

我使用VS 2008 SP1在運行帶有“高性能”電源設置的插入Vista的Core2 Duo筆記本電腦上使用VS 2008 SP1獲得了類似於使用C#與C 的相似結果(~1600 ms與~3800 ms)。看到優化的JIT的C#代碼有點棘手,但對於x86,它歸結為:

00000000 55               push        ebp  
00000001 8B EC            mov         ebp,esp 
00000003 57               push        edi  
00000004 56               push        esi  
00000005 53               push        ebx  
00000006 8B F1            mov         esi,ecx 
00000008 83 FE 02         cmp         esi,2 
0000000b 7D 07            jge         00000014 
0000000d 8B C6            mov         eax,esi 
0000000f 5B               pop         ebx  
00000010 5E               pop         esi  
00000011 5F               pop         edi  
00000012 5D               pop         ebp  
00000013 C3               ret              
            return fib(n - 1)   fib(n - 2);
00000014 8D 7E FF         lea         edi,[esi-1] 
00000017 83 FF 02         cmp         edi,2 
0000001a 7D 04            jge         00000020 
0000001c 8B DF            mov         ebx,edi 
0000001e EB 19            jmp         00000039 
00000020 8D 4F FF         lea         ecx,[edi-1] 
00000023 FF 15 F8 2F 12 00 call        dword ptr ds:[00122FF8h] 
00000029 8B D8            mov         ebx,eax 
0000002b 4F               dec         edi  
0000002c 4F               dec         edi  
0000002d 8B CF            mov         ecx,edi 
0000002f FF 15 F8 2F 12 00 call        dword ptr ds:[00122FF8h] 
00000035 03 C3            add         eax,ebx 
00000037 8B D8            mov         ebx,eax 
00000039 4E               dec         esi  
0000003a 4E               dec         esi  
0000003b 83 FE 02         cmp         esi,2 
0000003e 7D 04            jge         00000044 
00000040 8B D6            mov         edx,esi 
00000042 EB 19            jmp         0000005D 
00000044 8D 4E FF         lea         ecx,[esi-1] 
00000047 FF 15 F8 2F 12 00 call        dword ptr ds:[00122FF8h] 
0000004d 8B F8            mov         edi,eax 
0000004f 4E               dec         esi  
00000050 4E               dec         esi  
00000051 8B CE            mov         ecx,esi 
00000053 FF 15 F8 2F 12 00 call        dword ptr ds:[00122FF8h] 
00000059 03 C7            add         eax,edi 
0000005b 8B D0            mov         edx,eax 
0000005d 03 DA            add         ebx,edx 
0000005f 8B C3            mov         eax,ebx 
00000061 5B               pop         ebx  
00000062 5E               pop         esi  
00000063 5F               pop         edi  
00000064 5D               pop         ebp  
00000065 C3               ret  

In contrast to the C generated code (/Ox /Ob2 /Oi /Ot /Oy /GL /Gr):

與C 生成的代碼(/ Ox / Ob2 / Oi / Ot / Oy / GL / Gr)相反:

int fib(int n)
{ 
00B31000 56               push        esi  
00B31001 8B F1            mov         esi,ecx 
    if (n < 2) return n; 
00B31003 83 FE 02         cmp         esi,2 
00B31006 7D 04            jge         fib 0Ch (0B3100Ch) 
00B31008 8B C6            mov         eax,esi 
00B3100A 5E               pop         esi  
00B3100B C3               ret              
00B3100C 57               push        edi  
    return fib(n - 1)   fib(n - 2); 
00B3100D 8D 4E FE         lea         ecx,[esi-2] 
00B31010 E8 EB FF FF FF   call        fib (0B31000h) 
00B31015 8D 4E FF         lea         ecx,[esi-1] 
00B31018 8B F8            mov         edi,eax 
00B3101A E8 E1 FF FF FF   call        fib (0B31000h) 
00B3101F 03 C7            add         eax,edi 
00B31021 5F               pop         edi  
00B31022 5E               pop         esi  
} 
00B31023 C3               ret              

The C# version basically inlines fib(n-1) and fib(n-2). For a function that is so call heavy, reducing the number of function calls is the key to speed. Replacing fib with the following:

C#版本基本上內聯了fib(n-1)和fib(n-2)。對於一個如此強大的函數,減少函數調用的數量是速度的關鍵。用以下內容替換fib:

int fib(int n);

int fib2(int n) 
{ 
    if (n < 2) return n; 
    return fib(n - 1)   fib(n - 2); 
} 

int fib(int n)
{ 
    if (n < 2) return n; 
    return fib2(n - 1)   fib2(n - 2); 
} 

Gets it down to ~1900 ms. Incidentally, if I use #pragma inline_recursion(on) I get similar results with the original fib. Unrolling it one more level:

得到它~~ 1900毫秒。順便說一句,如果我使用#pragma inline_recursion(on),我會得到與原始fib相似的結果。再展開一個級別:

int fib(int n);

int fib3(int n) 
{ 
    if (n < 2) return n; 
    return fib(n - 1)   fib(n - 2); 
} 

int fib2(int n) 
{ 
    if (n < 2) return n; 
    return fib3(n - 1)   fib3(n - 2); 
} 

int fib(int n)
{ 
    if (n < 2) return n; 
    return fib2(n - 1)   fib2(n - 2); 
} 

Gets it down to ~1380 ms. Beyond that it tapers off.

得到它~1380毫秒。除此之外,它逐漸消失。

So it appears that the CLR JIT for my machine will inline recursive calls one level, whereas the C compiler will not do that by default.

因此,我的機器的CLR JIT似乎會將遞歸調用內聯到一個級別,而C 編譯器默認情況下不會這樣做。

If only all performance critical code were like fib!

如果只有所有性能關鍵代碼都像fib!

最佳答案:

DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
U19学习网站 » 在這種情況下,為什么.NET比C ++更快? - Why is .NET faster than C++ in this case? -开发者知识库