还是现在反过来了?

据我所知,c#在某些领域被证明比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列表初始化和填充。

其他回答

根据我的经验(这两种语言我都用过很多),与c++相比,c#的主要问题是内存消耗高,而且我还没有找到控制它的好方法。最终导致。net软件变慢的是内存消耗。

另一个因素是JIT编译器不能提供太多时间来进行高级优化,因为它在运行时运行,如果花费太多时间,最终用户会注意到它。另一方面,c++编译器有足够的时间在编译时进行优化。恕我直言,这个因素远没有内存消耗那么重要。

对于图形来说,标准的c#图形类比通过C/ c++访问的GDI慢得多。 我知道这与语言本身无关,更多的是与整个。net平台有关,但是图形是作为GDI替代品提供给开发人员的,它的性能非常糟糕,我甚至不敢用它来处理图形。

我们有一个简单的基准来查看图形库的速度,那就是在窗口中随机绘制线条。c++ /GDI在处理10000行代码时仍然很灵活,而c# /Graphics在处理1000行代码时却很难做到。

快了5个橘子。或者更确切地说:不可能有一个(正确的)笼统的答案。c++是一种静态编译语言(但也有配置文件引导的优化),c#在JIT编译器的帮助下运行。它们之间的差异如此之大,以至于像“快了多少”这样的问题都无法回答,甚至无法给出数量级。

我想这么说:编写更快代码的程序员,是那些更了解当前机器运行速度的人,顺便说一句,他们也是那些使用适当工具的人,这些工具允许精确的低级和确定性优化技术。由于这些原因,这些人使用C/ c++而不是c#。我甚至认为这是事实。

首先,我不同意这个问题的部分公认答案(并且得到了好评),我说:

为什么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++中你必须…呃,自己做出所有这些选择(甚至更多),理想情况下,这样你的解决方案才能最好地解决你正在处理的问题。

问问自己是否真的想要或需要该控件,因为即使对于上面的简单示例,您也可以看到尽管性能有了显著的改进,但它需要更深入的投资才能访问。