C#和C++的速度大比拼(第一部分)
發表于:2007-07-01來源:作者:點擊數:
標簽:
C#目前是微軟.NET平臺首推的應用程序 開發語言 。C#編寫的應用程序必須運行在一個特殊的環境中,即受控環境(managed)。與以往非受控(unmanaged)的C++相比,C#應用程序的性能到底如何呢?經過幾個方面的 性能測試 ,我們發現C#應用程序的運行速度遠遠不如
C#目前是微軟.NET平臺首推的應用程序
開發語言。C#編寫的應用程序必須運行在一個特殊的環境中,即受控環境(managed)。與以往非受控(unmanaged)的C++相比,C#應用程序的性能到底如何呢?經過幾個方面的
性能測試,我們發現C#應用程序的運行速度遠遠不如非受控C++應用程序。在這場速度的大比拼中,非受控C++具有明顯的優勢。它將一如既往地成為大多數
程序員的最愛。
本文擬通過一些正統的和非正統的性能
測試方法,對C#和C++程序進行測試。在這些測試的統計數據中。讀者會發現C#程序的性能到底如何。做為程序員,我對C++情有獨鐘。在我的職業生涯中,一直都在使用Visual C++。希望本文能給程序員們一點提示,以便在編寫不同的應用時選擇適合的編程語言。
Visual C++是Win32平臺上性能最好的編譯器之一,我想這已經成為一種共識。.NET是微軟提供的一種新的應用平臺。
首先我說明一下自己機器的軟硬件環境:
硬件環境:Dell Inspiron 3800 G700GT 筆記本電腦 CPU/PIII/700,ROM/128MB,HD/12GB。
軟件環境:Windows 2000 + SP2,.NET平臺 + Visual Studio.NET,Office
XP。
所有的測試均是在命令行狀態下以RELEASE模式編譯程序,而非Visual Studio IDE集成開發環境,并在命令行狀態下執行程序。沒有對編譯過程進行任何優化。
本文的測試由四個部分組成。其中包括用著名的埃拉托色尼過濾算法(Sieves of Eratosthenes)進行的測試及其它的單項測試,單項測試主要的考察.NET框架中特定項目的性能:
- Hello World 測試
.NET框架的一個問題是程序的啟動時間。因為.NET框架運行在Win32之上,因此要啟動一個.NET框架程序需要額外的啟動時間開銷。
- 埃拉托色尼過濾算法(Sieve of Eratosthenes)測試
這個過濾算法是一個古老的尋找素數的方法。因為開發這個算法是為人類所用,因此這個算法很占用CPU資源(非CPU優化),從而能提供非常好的基準反映人為因素。記住,編寫程序的總是人。
- 數據庫存取測試
當今應用程序服務器往往都要用到數據庫,所以我覺得用ADO.NET來測試C#的數據庫存取性能與用常規ADO測試Visual C++的數據庫存取性能進行比較是很能說明問題的一個好方法。
- XML測試
XML是一種最新的并且是流行的技術。因此許多人都會對用C# 和Visual C++解析XML的性能感興趣。
本文不打算對測試結果進行詳細解釋。在每一項測試中,我首先將用于測試的算法和代碼列出來。然后再列出測試結果數據。最后,針對這些數據勾勒出簡要的結論。
有一點在
測試過程中相當重要,那就是我試圖使兩個環境的測試代碼盡可能相同。這樣可以使得測試結果更有說服力。
Hello World Hello World測試程序主要是評測加載一個程序及其運行時環境所用的時間。C++的程序運行需要C運行庫,從所周知,這個庫是相當輕量級的。而C#程序的運行必須要加載.NET框架,從目前的情況看,這個框架無庸置疑不是一個輕量級的。
Hello World程序的C++代碼如下: 代碼一:helloworld.cpp
#include <
iostream>
int main(int argc, char *argv[])
{
s
td::cout << "Hello World" << std::endl;
return 0;
}; Hello World程序的C#代碼如下: 代碼二:helloworld2.cs
using System;
namespace HelloWorld
{
class Class1
{
static void Main(string[] args)
{
Console.WriteLine("Hello World");
}
}
} 從這個測試的結果中,我們可以看到程序在相應環境中的加載時間。對于一個只完成簡單任務的程序來說,無疑我們需要它能快速加載和退出。Perl腳本是個有代表性的例子,運行這種需要大量的加載時間,從而導致其不能滿足基于CGI且面向性能的Web站點的需要。這時,人們常常選擇C++程序替Perl腳本。但對于需要長時間處于激活狀態的程序,其加載時間相對運行時性能來說就顯得并不是那么很重要了。下表是十次測試的結果:
表一:Hello World 測試結果
序號 |
C++(~毫秒) |
C#(~毫秒) |
1 |
40 |
1221 |
2 |
20 |
121 |
3 |
10 |
130 |
4 |
10 |
100 |
5 |
10 |
110 |
6 |
10 |
130 |
7 |
10 |
120 |
8 |
10 |
140 |
9 |
10 |
150 |
10 |
20 |
140 |
平均值 |
15 |
235 |
測試結果的精確程度由GetTickCount函數的精度決定。其精度大概在百分之一秒。從結果我們可以得出這樣的結論。第一,冷啟動.NET應用過程所花費的時間比運行相同的應用多出一秒的時間。第二,啟動后的程序再運行時,在C++代碼大約是C#代碼運行時間開銷的十分之一。一般這種差別可以忽略不計。
埃拉托色尼過濾算法測試
埃拉托色尼過濾算法測試程序評估基本的整型算法和比較邏輯。這個算法歷史悠久,它早在計算機出現之前就已經存在。因此用它來評估人們在各種環境中創建的算法性能具有一定的典型性或代表性。
埃拉托色尼過濾算法的C++代碼如下:
代碼三:sieve.cpp
#include <
windows.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdlib>
using namespace std;
int main(int argc, char *argv[])
{
if (argc != 2)
{
std::cerr << "Usage:\tsieve [iterations]\n";
return 1;
};
size_t NUM = atoi(argv[1]);
DWORD dw = ::GetTickCount();
vector
primes(8192 + 1);
vector::iterator pbegin = primes.begin();
vector::iterator begin = pbegin + 2;
vector::iterator end = primes.end();
while (NUM--)
{
fill(begin, end, 1);
for (vector::iterator i = begin;
i < end; ++i)
{
if (*i)
{
const size_t p = i - pbegin;
for (vector::iterator k = i + p;
k < end; k += p)
{
*k = 0;
}
}
}
}
DWORD dw2 = ::GetTickCount();
std::cout << "Milliseconds = " << dw2-dw
<< std::endl;
return 0;
}下面是埃拉托色尼過濾算法的C#代碼: 代碼四:
using System;
namespace Sieve
{
class Class1
{
static void Main(string[] args)
{
if (args.Length != 1)
{
Console.WriteLine("Usage:\tsieve "
"[iterations]");
return;
}
int NUM = int.Parse(args[0]);
long dt = DateTime.Now.Ticks;
int[] primes = new int[8192+1];
int pbegin = 0;
int begin = 2;
int end = 8193;
while (NUM-- != 0)
{
for (int i = 0; i < end; i++)
{
primes[i] = 1;
}
for (int i = begin; i < end; ++i)
{
if (primes[i] != 0)
{
int p = i - pbegin;
for (int k = i + p; k < end; k += p)
{
primes[k] = 0;
};
}
};
};
long dt2 = DateTime.Now.Ticks;
System.Console.WriteLine("Milliseconds = {0}",
(dt2-dt)/10000);
}
}
} 測試的結果并不足以說明那一種環境更快。在這兩個語言的測試中,我旨在說明哪一種語言的構造對測試的結果影響最大。當你基于性能的考慮來選擇某種語言時,應該直接考慮心需要哪種類型的性能。在這里,埃拉托色尼過濾算法測試的是循環構造以及比較邏輯和整數基本類型的處理。下面是十次測試,每次進行10000次重復的測試結果:
表二:過濾算法測試結果
序號 |
C++(~毫秒) |
C#(~毫秒) |
1 |
1342 |
2724 |
2 |
1342 |
2714 |
3 |
1342 |
2724 |
4 |
1342 |
2724 |
5 |
1342 |
2734 |
6 |
1342 |
2724 |
7 |
1362 |
2734 |
8 |
1352 |
2734 |
9 |
1362 |
2724 |
10 |
1352 |
2724 |
平均值 |
1348 |
2726 |
這個結果很能說明問題。整數計算C#所花的時間是C++的兩倍。所以對于一個邏輯復雜的服務器來說,使用非受管C++代碼比C#代碼更適合。
上面的C++代碼和C#代碼之間有一個差別,即C#使用的是本機數組,而C++代碼用的是向量模板類,我用本機數組重寫了C++代碼,按說應該更快。是結果不是這樣,本機C++數組執行用時是1900毫秒。(待續)
原文轉自:http://www.anti-gravitydesign.com