还是现在反过来了?
据我所知,c#在某些领域被证明比c++更快,但我从来没有勇气亲自测试它。
我想你们任何人都可以详细解释这些差异,或者告诉我有关信息的正确位置。
还是现在反过来了?
据我所知,c#在某些领域被证明比c++更快,但我从来没有勇气亲自测试它。
我想你们任何人都可以详细解释这些差异,或者告诉我有关信息的正确位置。
当前回答
c#和c++在性能方面有一些主要的区别:
c#是基于GC /堆的。分配和GC本身是内存访问的非局部性开销 多年来,c++优化器已经变得非常好。JIT编译器无法达到相同的级别,因为它们只有有限的编译时间,并且看不到全局作用域
除此之外,程序员的能力也很重要。我见过一些糟糕的c++代码,其中的类通过值作为参数传递。在c++中,如果你不知道自己在做什么,实际上会让性能变差。
其他回答
In theory, for long running server-type application, a JIT-compiled language can become much faster than a natively compiled counterpart. Since the JIT compiled language is generally first compiled to a fairly low-level intermediate language, you can do a lot of the high-level optimizations right at compile time anyway. The big advantage comes in that the JIT can continue to recompile sections of code on the fly as it gets more and more data on how the application is being used. It can arrange the most common code-paths to allow branch prediction to succeed as often as possible. It can re-arrange separate code blocks that are often called together to keep them both in the cache. It can spend more effort optimizing inner loops.
我怀疑。net或任何jre都能做到这一点,但早在我上大学的时候就有人在研究这一点,所以认为这类东西很快就会在现实世界中找到自己的方式也不是不合理的。
首先,我不同意这个问题的部分公认答案(并且得到了好评),我说:
为什么jit代码比适当优化的c++(或其他没有运行时开销的语言)运行得慢,实际上有很多原因。 程序包括:
根据定义,在运行时用于jit代码的计算周期在程序执行中不可用。 JITter中的任何热路径都将与你的代码竞争指令和CPU中的数据缓存。我们知道缓存在性能方面占主导地位,而像c++这样的原生语言在设计上并没有这种类型的争用。 运行时优化器的时间预算必然比编译时优化器的时间预算更有限(正如另一个评论者指出的那样)。
底线:最终,您几乎肯定能够在c++中创建比在c#中更快的实现。
现在,说了这么多,速度到底有多快是无法量化的,因为有太多的变量:任务、问题领域、硬件、实现质量和许多其他因素。您将在您的场景上运行测试,以确定性能上的差异,然后决定是否值得额外的努力和复杂性。
这是一个很长很复杂的话题,但为了完整起见,我觉得值得一提的是,c#的运行时优化器非常出色,能够在运行时执行某些c++编译时(静态)优化器无法实现的动态优化。即便如此,优势仍然主要体现在本机应用程序方面,但动态优化器是上面给出的“几乎肯定”限定符的原因。
--
在相对性能方面,我也被我在其他一些答案中看到的数字和讨论所困扰,所以我想我应该插话,同时为我上面所做的陈述提供一些支持。
这些基准测试的很大一部分问题是,你不能像写c#一样写c++代码,并期望得到具有代表性的结果(例如。在c++中执行成千上万的内存分配将会给你可怕的数字。)
相反,我编写了稍微更习惯的c++代码,并与@Wiory提供的c#代码进行了比较。我对c++代码所做的两个主要更改是:
使用向量::储备() 将2d数组平摊到1d以获得更好的缓存位置(连续块)
c#(。净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);
}
运行时间(发布):初始: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#: 289毫秒,c++ 152毫秒(大约快90%)
观察
Changing the C# implementation to the same 1d array implementation yielded Init: 40ms, Fill: 171ms, Total: 211ms (C++ was still almost 40% faster). It is much harder to design and write "fast" code in C++ than it is to write "regular" code in either language. It's (perhaps) astonishingly easy to get poor performance in C++; we saw that with unreserved vectors performance. And there are lots of pitfalls like this. C#'s performance is rather amazing when you consider all that is going on at runtime. And that performance is comparatively easy to access. More anecdotal data comparing the performance of C++ and C#: https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=gpp&lang2=csharpcore
归根结底,c++为您提供了对性能的更多控制。你想用指针吗?一个参考吗?栈内存?堆吗?动态多态还是用静态多态(通过模板/CRTP)消除虚表的运行时开销?在c++中你必须…呃,自己做出所有这些选择(甚至更多),理想情况下,这样你的解决方案才能最好地解决你正在处理的问题。
问问自己是否真的想要或需要该控件,因为即使对于上面的简单示例,您也可以看到尽管性能有了显著的改进,但它需要更深入的投资才能访问。
我已经在c++和c#等效中测试了vector - List和简单的2d数组。
我使用Visual c# / c++ 2010 Express版本。这两个项目都是简单的控制台应用程序,我在标准(没有自定义设置)发布和调试模式下对它们进行了测试。 c#列表在我的电脑上运行得更快,c#中的数组初始化也更快,数学运算更慢。
我使用英特尔Core2Duo P8600@2.4GHz, c# - . net 4.0。
我知道向量实现不同于c#列表,但我只是想测试我将用于存储我的对象的集合(并能够使用索引访问器)。
当然,您需要清除内存(比如每次使用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++
600 / 606 ms array init 200 / 270毫秒阵列填充, 1秒/13秒矢量初始化和填充。
(是的,13秒,我总是在调试模式下遇到列表/向量的问题。)
C#:
20 / 20 ms数组初始化 403 / 440毫秒阵列填充, 710 / 742 ms列表初始化和填充。
垃圾收集是Java#不能用于实时系统的主要原因。
GC什么时候会发生? 需要多长时间?
这是不确定的。
根据我的经验(这两种语言我都用过很多),与c++相比,c#的主要问题是内存消耗高,而且我还没有找到控制它的好方法。最终导致。net软件变慢的是内存消耗。
另一个因素是JIT编译器不能提供太多时间来进行高级优化,因为它在运行时运行,如果花费太多时间,最终用户会注意到它。另一方面,c++编译器有足够的时间在编译时进行优化。恕我直言,这个因素远没有内存消耗那么重要。