或者它现在反过来了?
从我所听到的有些领域,C#证明比C ++更快,但我从来没有勇气自己测试它。
你们中的任何一个人都可以详细解释这些差异,或者将我指向正确的地方以获取相关信息。
没有严格的理由说明基于字节码的语言(如C#或Java)具有JIT不能像C ++代码一样快。但是,C ++代码在很长一段时间内都显着提高了速度,而且在很多情况下今天仍然如此。这主要是由于更高级的JIT优化实现起来很复杂,而真正酷的优化只是刚刚到来。
因此,在许多情况下,C ++更快。但这只是答案的一部分。 C ++实际上更快的情况是高度优化的程序,专家程序员彻底优化了代码的地狱。这不仅非常耗时(并且因此昂贵),而且还通常由于过度优化而导致错误。
另一方面,解释语言中的代码在运行时的更高版本(.NET CLR或Java VM)中变得更快,而无需执行任何操作。 JIT编译器可以做很多有用的优化,这些优化在带有指针的语言中根本不可能。此外,一些人认为垃圾收集通常应该与手动内存管理一样快或者更快,并且在许多情况下它是。您通常可以在C ++或C中实现并实现所有这些功能,但它会更加复杂且容易出错。
正如唐纳德克努特所说,“过早优化是万恶之源”。如果您确实知道您的应用程序将主要包含非常高性能的算法,并且它将成为瓶颈,并且它在C ++中肯定会更快,并且您确信C ++不会与您的其他产品冲突要求,去C ++。在任何其他情况下,专注于首先以最适合您的语言正确实现您的应用程序,然后在运行速度太慢时找到性能瓶颈,然后考虑如何优化代码。在最坏的情况下,您可能需要通过外部函数接口调用C代码,因此您仍然可以使用较低级别的语言编写关键部分。
请记住,优化正确的程序相对容易,但更难以纠正优化的程序。
给出速度优势的实际百分比是不可能的,这在很大程度上取决于您的代码。在许多情况下,编程语言实现甚至不是瓶颈。以http://benchmarksgame.alioth.debian.org/的基准测试为基础,有很多怀疑论,因为这些测试算术代码很可能与你的代码完全不同。
我们不得不确定C#在性能上是否与C ++相当,我为此编写了一些测试程序(对于这两种语言使用Visual Studio 2005)。事实证明,没有垃圾收集,只考虑语言(而不是框架),C#与C ++的性能基本相同。 C#中的内存分配比C ++中更快,当数据大小超出缓存行边界时,C#在确定性方面略有优势。然而,所有这些最终都要付出代价,并且由于垃圾收集,C#的非确定性性能命中形式会产生巨大的成本。
像往常一样,这取决于应用程序。在某些情况下,C#的速度可能会慢得多,而其他情况下C ++的速度要慢5到10倍,特别是在操作可以轻松进行SIMD的情况下。
我知道这不是你所要求的,但C#通常比C ++写得更快,这在商业环境中是一个很大的好处。
C / C ++可以在程序中执行得更好,在这些程序中有大型数组或重型循环/迭代数组(任何大小)。这就是图形在C / C ++中通常要快得多的原因,因为重型阵列操作几乎是所有图形操作的基础。由于所有的安全检查,.NET在数组索引操作中的速度非常慢,对于多维数组尤其如此(是的,矩形C#数组甚至比锯齿状C#数组慢)。
如果直接使用指针并避免使用Boost,std::vector
和其他高级容器,以及inline
可能的每个小功能,C / C ++的奖金最为明显。尽可能使用旧式数组。是的,您将需要更多代码行来完成与Java或C#相同的操作,因为您避免使用高级容器。如果你需要一个动态大小的数组,你只需要记住将你的new T[]
与相应的delete[]
语句配对(或使用std::unique_ptr
) - 额外速度的价格是你必须更仔细地编码。但作为交换,你可以摆脱托管内存/垃圾收集器的开销,这可能很容易占Java和.NET中大量面向对象程序的执行时间的20%或更多,以及那些大量托管程序内存数组索引成本。在某些特定情况下,C ++应用程序也可以从一些漂亮的编译器开关中受益。
我是C,C ++,Java和C#的专家程序员。我最近有机会在后3种语言中实现完全相同的算法程序。该程序有很多数学和多维数组操作。我用所有3种语言对其进行了大量优化。结果是我通常在不太严格的比较中看到的典型结果:Java比C#快大约1.3倍(大多数JVM比CLR更优化),而C ++原始指针版本的速度比C#快大约2.1倍。请注意,C#程序仅使用安全代码 - 我认为您在使用unsafe
关键字之前也可以使用C ++编写代码。
为了避免有人认为我有反对C#的东西,我最后会说C#可能是我最喜欢的语言。它是迄今为止我遇到的最合乎逻辑,最直观,最快速的开发语言。我在C#中做了所有的原型设计。与Java相比,C#语言有许多小的,微妙的优势(是的,我知道微软有机会通过较晚进入游戏并可以复制Java来修复Java的许多缺点)。吐司到Java的Calendar
类任何人?如果微软花费了大量精力来优化CLR和.NET JITter,那么C#可以认真接管。我真的很惊讶他们还没有 - 他们在C#语言中做了很多事情,为什么不跟着重击编译器优化呢?也许如果我们都乞求。
>据我所知......
您的困难似乎在于决定您所听到的内容是否可信,并且当您尝试评估此网站上的回复时,将会重复这一困难。
你怎么决定人们在这里说的话比你原来听到的更可靠或更不可信?
一种方法是要求证据。
当有人声称“有些领域C#证明比C ++更快”时,问他们为什么这么说,请他们告诉你测量结果,让他们向你展示程序。有时他们会犯错误。有时你会发现他们只是表达了一种意见,而不是分享他们可以证明是真实的东西。
通常情况下,信息和意见会混淆在人们所声称的内容中,你必须尝试找出哪个是哪个。例如,来自本论坛的回复:
.NET语言可以像C ++代码一样快,甚至更快,但C ++代码将具有更恒定的吞吐量,因为.NET运行时必须暂停GC,即使它对其暂停非常聪明。
因此,如果您的某些代码必须始终如一地快速运行而没有任何暂停,那么即使您对运行时GC非常小心,.NET也会在某些时候引入延迟。
对于“令人难以置信的并行”问题,当在C ++上使用英特尔TBB和OpenMP时,我发现与使用C#和TPL完成的类似(纯数学)问题相比,性能提升了大约10倍。 SIMD是C#无法竞争的一个领域,但我也觉得TPL有相当大的开销。
也就是说,我只使用C ++进行性能关键任务,我知道我将能够多线程并快速获得结果。对于其他一切,C#(偶尔也是F#)就好了。
没有真正明确的答案,这是一个非常模糊的问题。
例如;我宁愿玩用C ++创建的3D游戏而不是C#,因为性能肯定要好得多。 (而且我知道XNA等等,但它并没有接近真实的东西)。
另一方面,如前所述;你应该用一种语言进行开发,让你快速做你想做的事,然后在必要时进行优化。
理论上,对于长时间运行的服务器类型应用程序,JIT编译的语言可以比本机编译的语言快得多。由于JIT编译语言通常首先编译为相当低级的中间语言,因此无论如何都可以在编译时进行大量的高级优化。最大的优势在于JIT可以继续重新编译代码段,因为它获得了有关应用程序使用方式的越来越多的数据。它可以安排最常见的代码路径,以允许分支预测尽可能频繁地成功。它可以重新排列通常一起调用的单独代码块,以便将它们保存在缓存中。它可以花费更多精力来优化内部循环。
我怀疑这是由.NET还是任何一个JRE完成的,但是当我在大学时它正在被研究过,所以认为这些东西很快就会在某个时刻进入现实世界并不是不合理的。
需要密集内存访问的应用程序,例如在非托管环境(C ++)中编写图像操作通常比托管(C#)更好。使用指针算术的优化内循环在C ++中更容易控制。在C#中,您可能需要使用不安全的代码来获得接近相同的性能。
C#可能不会更快,但它会让你/我更快。这是我做的最重要的衡量标准。 :)
我用C ++测试了vector
和C#等价 - List
和简单的2d数组。
我正在使用Visual C#/ C ++ 2010 Express版本。这两个项目都是简单的控制台应用程序,我已经在标准(无自定义设置)发布和调试模式下测试它们。 C#列表在我的电脑上运行得更快,数组初始化在C#中也更快,数学运算速度更慢。
我使用的是Intel Core2Duo [email protected],C# - .NET 4.0。
我知道向量实现与C#list不同,但我只想测试用于存储对象的集合(并且能够使用索引访问器)。
当然你需要清除内存(让我们说new
的每次使用),但我想保持代码简单。
C ++矢量测试:
static void TestVector()
{
clock_t start,finish;
start=clock();
vector<vector<double>> myList=vector<vector<double>>();
int i=0;
for( i=0; i<500; i++)
{
myList.push_back(vector<double>());
for(int j=0;j<50000;j++)
myList[i].push_back(j+i);
}
finish=clock();
cout<<(finish-start)<<endl;
cout<<(double(finish - start)/CLOCKS_PER_SEC);
}
C#列表测试:
private static void TestVector()
{
DateTime t1 = System.DateTime.Now;
List<List<double>> myList = new List<List<double>>();
int i = 0;
for (i = 0; i < 500; i++)
{
myList.Add(new List<double>());
for (int j = 0; j < 50000; j++)
myList[i].Add(j *i);
}
DateTime t2 = System.DateTime.Now;
Console.WriteLine(t2 - t1);
}
C ++ - 数组:
static void TestArray()
{
cout << "Normal array test:" << endl;
const int rows = 5000;
const int columns = 9000;
clock_t start, finish;
start = clock();
double** arr = new double*[rows];
for (int i = 0; i < rows; i++)
arr[i] = new double[columns];
finish = clock();
cout << (finish - start) << endl;
start = clock();
for (int i = 0; i < rows; i++)
for (int j = 0; j < columns; j++)
arr[i][j] = i * j;
finish = clock();
cout << (finish - start) << endl;
}
C# - 数组:
private static void TestArray()
{
const int rows = 5000;
const int columns = 9000;
DateTime t1 = System.DateTime.Now;
double[][] arr = new double[rows][];
for (int i = 0; i < rows; i++)
arr[i] = new double[columns];
DateTime t2 = System.DateTime.Now;
Console.WriteLine(t2 - t1);
t1 = System.DateTime.Now;
for (int i = 0; i < rows; i++)
for (int j = 0; j < columns; j++)
arr[i][j] = i * j;
t2 = System.DateTime.Now;
Console.WriteLine(t2 - t1);
}
时间:(发布/调试)
C ++
(是的,13秒,我在调试模式下总是遇到列表/向量问题。)
C#:
这得看情况。如果字节码被翻译成机器码(而不仅仅是JIT)(我的意思是如果你执行程序),如果你的程序使用了很多分配/解除分配,它可能会更快,因为GC算法只需要一次传递(理论上)通过整个内存一次,但正常的malloc / realloc / free C / C ++调用会导致每次调用的开销(调用开销,数据结构开销,缓存未命中;))。
所以它在理论上是可行的(也适用于其他GC语言)。
我没有真正看到在大多数应用程序中不能将metaprogramming与C#一起使用的极端缺点,因为大多数程序员无论如何都不使用它。
另一个很大的优点是SQL,如LINQ“扩展”,为编译器提供了优化对数据库的调用的机会(换句话说,编译器可以将整个LINQ编译为一个“blob”二进制文件,其中被调用的函数被内联或为您的使用进行了优化,但我在这里推测)。
我想有些应用程序用C#编写的应用程序运行速度很快,而且有更多的C ++编写的应用程序运行得很快(C ++刚刚老了......并且也使用了UNIX ...) - 问题确实是 - 那是什么东西,用户和开发者都抱怨... 嗯,恕我直言,在C#的情况下,我们有非常舒适的UI,非常好的库层次结构,以及CLI的整个界面系统。在C ++的情况下,我们有模板,ATL,COM,MFC和已经编写并运行OpenGL,DirectX等代码的整个shebang ...开发人员抱怨在C#的情况下不可避免地升级GC调用(意味着程序运行速度快,并且一秒钟 - 砰!它被卡住了。 用C#编写代码非常简单快速(不要忘记这也会增加错误的机会。在C ++的情况下,开发人员抱怨内存泄漏, - 意味着粉碎,DLL之间的调用,以及“DLL地狱” - 问题与新的支持和替换库... 我认为您在编程语言中拥有的技能越多,您的软件的质量(和速度)就越高。
我会这样说:编写速度更快的代码的程序员是那些更了解当前机器运行速度的人,顺便说一句,他们也是那些使用适当的工具来实现精确的低级和确定性的人。优化技术。出于这些原因,这些人是使用C / C ++而不是C#的人。我会说这是一个事实。
>毕竟,答案必须在某个地方,不是吗? :)
嗯,不。
正如几份答复所指出的那样,这个问题的指定方式不足以引发回答问题,而非答案。采取一种方式:
然后是哪些节目?哪台机器?哪个OS?哪个数据集?
如果我没弄错的话,C#模板是在运行时确定的。这必须比C ++的编译时模板慢。
当你接受许多其他人提到的所有其他编译时优化,以及缺乏安全性时,确实意味着更快的速度......
我想说C ++在原始速度和最小内存消耗方面是明显的选择。但这也转化为更多时间开发代码并确保您不会泄漏内存或导致任何空指针异常。
判决:
这实际上取决于您在代码中尝试完成的任务。我听说在VB.NET,C#和托管C ++之间存在性能差异,这只是都市传奇的一部分。但是,我发现,至少在字符串比较中,托管C ++胜过C#,而这反过来又打败了VB.NET。
我绝不会对语言之间的算法复杂性进行任何详尽的比较。我也只是使用每种语言的默认设置。在VB.NET中,我使用设置来要求声明变量等。以下是我用于托管C ++的代码:(正如您所看到的,此代码非常简单)。我在Visual Studio 2013中使用.NET 4.6.2在其他语言中运行相同的操作。
#include "stdafx.h"
using namespace System;
using namespace System::Diagnostics;
bool EqualMe(String^ first, String^ second)
{
return first->Equals(second);
}
int main(array<String ^> ^args)
{
Stopwatch^ sw = gcnew Stopwatch();
sw->Start();
for (int i = 0; i < 100000; i++)
{
EqualMe(L"one", L"two");
}
sw->Stop();
Console::WriteLine(sw->ElapsedTicks);
return 0;
}
C#和C ++在性能方面存在一些主要差异:
除此之外,程序员的能力也起着重要作用。我已经看到了糟糕的C ++代码,其中类通过值作为参数传递到各处。如果你不注意,你实际上可以在C ++中使它变得更糟。
受此启发,我做了一个快速测试,大多数程序需要60%的常用指令。
这是C#代码:
for (int i=0; i<1000; i++)
{
StreamReader str = new StreamReader("file.csv");
StreamWriter stw = new StreamWriter("examp.csv");
string strL = "";
while((strL = str.ReadLine()) != null)
{
ArrayList al = new ArrayList();
string[] strline = strL.Split(',');
al.AddRange(strline);
foreach(string str1 in strline)
{
stw.Write(str1 + ",");
}
stw.Write("\n");
}
str.Close();
stw.Close();
}
有意使用字符串数组和arraylist来包含这些指令。
这是c ++代码:
for (int i = 0; i<1000; i++)
{
std::fstream file("file.csv", ios::in);
if (!file.is_open())
{
std::cout << "File not found!\n";
return 1;
}
ofstream myfile;
myfile.open ("example.txt");
std::string csvLine;
while (std::getline(file, csvLine))
{
std::istringstream csvStream(csvLine);
std::vector csvColumn;
std::string csvElement;
while( std::getline(csvStream, csvElement, ‘,’) )
{
csvColumn.push_back(csvElement);
}
for (std::vector::iterator j = csvColumn.begin(); j != csvColumn.end(); ++j)
{
myfile << *j << ", ";
}
csvColumn.clear();
csvElement.clear();
csvLine.clear();
myfile << "\n";
}
myfile.close();
file.close();
}
我使用的输入文件大小是40 KB。
这是结果 -
哦,但这是在Linux上... C#在Mono上运行...而C ++在g ++上运行。
好的,这是我在Windows上得到的 - Visual Studio 2003:
它的五个橙子更快。或者更确切地说:没有(正确的)一揽子答案。 C ++是一种静态编译的语言(但是,也有配置文件引导优化),C#在JIT编译器的帮助下运行。存在很多差异,诸如“快多快”的问题无法回答,甚至不能达到数量级。
首先,我将通过陈述:不同意对此问题的部分接受(以及良好的投票)答案:
实际上有很多原因导致JITted代码运行速度慢于正确优化的C ++(或其他没有运行时开销的语言)程序,包括:
结论:最终,您几乎可以肯定能够在C ++中创建比C#更快的实现。
现在,有了这样说,实际上还有多快不可量化,因为变量太多:任务,问题域,硬件,实现质量以及许多其他因素。您将对场景运行测试以确定性能差异,然后确定是否值得额外的工作量和复杂性。
这是一个非常漫长而复杂的主题,但我觉得为了完整起见,值得一提的是C#的运行时优化器非常出色,并且能够在运行时执行某些动态优化,这些优化在C ++编译时是不可用的(静态)优化器。即便如此,优势仍然通常在本机应用程序的法庭上,但动态优化器是上面给出的“几乎肯定”限定符的原因。
--
在相对表现方面,我也被其他一些答案所看到的数字和讨论所打扰,所以我想我会在同一时间为我上面的陈述提供一些支持。
这些基准测试的问题很大一部分就是你不能像编写C#一样编写C ++代码并期望获得有代表性的结果(例如,在C ++中执行数千个内存分配会给你带来可怕的数字。)
相反,我写了稍微更惯用的C ++代码,并与提供的C#代码@Wiory进行了比较。我对C ++代码所做的两个主要更改是:
1)使用了vector :: reserve()
2)将2d数组展平为1d以实现更好的缓存局部性(连续块)
C#(.NET 4.6.1)
private static void TestArray()
{
const int rows = 5000;
const int columns = 9000;
DateTime t1 = System.DateTime.Now;
double[][] arr = new double[rows][];
for (int i = 0; i < rows; i++)
arr[i] = new double[columns];
DateTime t2 = System.DateTime.Now;
Console.WriteLine(t2 - t1);
t1 = System.DateTime.Now;
for (int i = 0; i < rows; i++)
for (int j = 0; j < columns; j++)
arr[i][j] = i;
t2 = System.DateTime.Now;
Console.WriteLine(t2 - t1);
}
运行时间(Release):Init:124ms,填充:165ms
C ++ 14(Clang v3.8 / C2)
#include <iostream>
#include <vector>
auto TestSuite::ColMajorArray()
{
constexpr size_t ROWS = 5000;
constexpr size_t COLS = 9000;
auto initStart = std::chrono::steady_clock::now();
auto arr = std::vector<double>();
arr.reserve(ROWS * COLS);
auto initFinish = std::chrono::steady_clock::now();
auto initTime = std::chrono::duration_cast<std::chrono::microseconds>(initFinish - initStart);
auto fillStart = std::chrono::steady_clock::now();
for(auto i = 0, r = 0; r < ROWS; ++r)
{
for (auto c = 0; c < COLS; ++c)
{
arr[i++] = static_cast<double>(r * c);
}
}
auto fillFinish = std::chrono::steady_clock::now();
auto fillTime = std::chrono::duration_cast<std::chrono::milliseconds>(fillFinish - fillStart);
return std::make_pair(initTime, fillTime);
}
运行时间(释放):初始值:398μs(是的,那是微秒),填充:152ms
意见
最重要的是,C ++为您提供了更多的性能控制。你想用指针吗?参考?堆栈内存?堆?动态多态或消除静态多态的vtable的运行时开销(通过模板/ CRTP)?在C ++中,你必须......呃,自己做出所有这些选择(以及更多),理想情况下,你的解决方案最能解决你正在解决的问题。
问问自己你是否真的想要或需要这种控制,因为即使是上面的小例子,你也可以看到虽然性能有了显着提高,但它需要更深入的投资才能获得。
根据我的经验(我用两种语言都做了很多工作),C#与C ++相比的主要问题是高内存消耗,我还没有找到一种很好的方法来控制它。内存消耗最终会减慢.NET软件的速度。
另一个因素是JIT编译器不能承受太多时间来进行高级优化,因为它在运行时运行,如果花费太多时间,最终用户会注意到它。另一方面,C ++编译器始终需要在编译时进行优化。这个因素远没有内存消耗那么重要,恕我直言。
在编译时可以预先确定多态决策的情况下,C ++仍然具有优势(并将在未来几年内发挥作用)的一种特殊情况发生。
通常,封装和延迟决策是一件好事,因为它使代码更加动态,更容易适应不断变化的需求并更容易用作框架。这就是为什么C#中的面向对象编程非常有效并且可以在术语“泛化”下概括的原因。不幸的是,这种特殊的泛化在运行时需要付出代价。
通常,这种成本是非实质性的,但是有些应用程序中虚拟方法调用和对象创建的开销可能会有所不同(特别是因为虚方法会阻止其他优化,例如方法调用内联)。这就是C ++具有巨大优势的地方,因为您可以使用模板来实现不同类型的泛化,这种泛化对运行时没有影响,但不一定比OOP更少多态。事实上,构成OOP的所有机制都可以仅使用模板技术和编译时解析来建模。
在这种情况下(并且不可否认,它们通常仅限于特殊问题域),C ++赢得了C#和类似的语言。
C ++(或者C就此而言)为您提供了对数据结构的细粒度控制。如果你想捏捏你有这个选择。使用Java / .NET库的内部数据结构的大型托管Java或.NET应用程序(OWB,Visual Studio 2005)随身携带。我已经看到OWB设计师会话使用超过400 MB的RAM和BIDS用于立方体或ETL设计也进入100的MB。
在可预测的工作负载(例如多次重复进程的基准测试)上,JIT可以为您提供经过充分优化的代码,使其没有实际差异。
IMO在大型应用程序上的区别不在于JIT与代码本身正在使用的数据结构。如果应用程序占用大量内存,则缓存使用效率会降低。现代CPU上的高速缓存未命中非常昂贵。在C或C ++真正获胜的地方,您可以优化数据结构的使用,以便与CPU缓存很好地协同工作。
对于图形,标准C#Graphics类比通过C / C ++访问的GDI慢。我知道这与语言本身无关,更多的是与整个.NET平台有关,但Graphics是作为GDI替代品提供给开发人员的,它的性能非常糟糕我甚至不敢做图形用它。
我们有一个简单的基准测试,用于查看图形库的速度,并且只是在窗口中绘制随机线。 C ++ / GDI仍然很容易使用10000行,而C#/ Graphics难以实时执行1000行。
垃圾收集是Java#不能用于实时系统的主要原因。
这是不确定的。