C ++与C#阵列性能问题

时间:2017-03-11 22:51:27

标签: c# c++ arrays performance

所以,我有一种情况,我必须处理大型(多维)数组,只是想知道C#或C ++是否会表现更好。 (注意:我是C ++的初学者,所以不要过多地了解它是如何运作的!)。我认为在数组方面,两种语言的表现都差不多,也许C ++可能稍好一些但是:结果告诉其他故事:

1012ms in C++ @32Bit
1020ms in C++ @32Bit
1002ms in C++ @32Bit

1155ms in C++ @64Bit
1098ms in C++ @64Bit
1122ms in C++ @64Bit
1136ms in C++ @64Bit


523ms in C# @32-Bit
545ms in C# @32-Bit
537ms in C# @32-Bit
536ms in C# @32-Bit

473ms in C# @64-Bit
501ms in C# @64-Bit
470ms in C# @64-Bit
498ms in C# @64-Bit

我在x86执行了一次Test运行,在x64架构执行了一次。这里有两件事:为什么C#比C ++好几乎两倍?为什么C#在x64-Mode和x86-mode中的C ++实际上更快?!?我真的没想到会发生这种情况。

正如我所说,我目前没有C +经验 - 编程,但我尽力在C ++中复制我的C#-Code。

这里是代码: C#

for (int j = 0; j < 4; j++)
{
    Stopwatch sw = new Stopwatch();
    sw.Start();

    struct1[] s1 = new struct1[20000000];
    int length = 20000000;

    for (int i = 0; i < length; i++)
    {
        s1[i] = new struct1();
        s1[i].samplechar = 'c';
        s1[i].sampleInt = i * 2;
        s1[i].sampledouble = Math.Sqrt(i);
    }

    sw.Stop();
    GC.Collect();
    Console.WriteLine(sw.ElapsedMilliseconds + "ms in C# @...-Bit");
}

AND struct1:

public struct struct1
{
    public int sampleInt;
    public double sampledouble;
    public char samplechar;
}

C ++:

for (int j = 0; j < 4; j++)
{
    auto begin = std::chrono::high_resolution_clock::now();

    struct1* s1 = new struct1[20000000];
    int length = 20000000;

    for (int i = 0; i < length; i++)
    {
        s1[i].sampleChar = 'c';
        s1[i].sampleInt = i * 2;
        s1[i].sampleDouble = sqrt(i);
    }
    auto end = std::chrono::high_resolution_clock::now();       

    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << "ms in C++ @64Bit" << std::endl;

    free(s1);

}

struct1:

struct struct1 {
public:
    int sampleInt;
    int sampleDouble;
    char sampleChar;

};

注意:我没有将垃圾收集/免费包含在性能测量中,因为 - 在我的情况下 - 只要程序运行,就会有一个巨大的数组存在。而且我认为很明显,除非你想杀死你的机器,否则会经常创建/删除这些大小的数组...

注2:另一个令人困惑的事情:虽然C ++消耗大约250MB的RAM,但C#需要500MB。但为什么呢?

提前感谢任何解释。也许我只是弄错了,失败只是坐在显示器后面,但我虽然对我为何得到这些结果感兴趣。

编辑:我在Windows 10上运行Visual Studio 2017RC。禁用C ++优化(/ Od)

2 个答案:

答案 0 :(得分:0)

使用正确的优化和编译器设置,C ++版本应该至少与C#版本一样快。请注意,您没有完全相同地计算时间(看看您是否可以在C ++中使用StopWatch进行尝试?) - 请参阅此问题以获取更多详细信息:resolution of std::chrono::high_resolution_clock doesn't correspond to measurements - 这是很可能是你不同时间的来源(特别是为什么C ++实现的测量时间更长)。 StopWatch比您在std::chrono::high_resolution_clock的VisualStudio / Windows实现中使用的更准确。

还要记住,你实际上并没有处理多维数组(例如C#中的int[,]) - 你只是在处理一组结构。对于它的价值,我的回忆是实际多维数组的CLR实现并不是为大型集合的性能而构建的 - 它可能构建一个更快的(如果实际上你需要多维数组而不仅仅是结构数组) )。

这里更大的优势可能是能够更严格地控​​制内存管理 - 如果你正在分配大型结构数组,你可以使用C或C ++更密切地控制分配的生命周期。垃圾收集环境。您也可以更轻松/自然地使用指针算法和内存复制 - 尽管这在C#中的unsafe上下文中也是完全可能的。与safe上下文中的“vanilla”C#实现相比,可能会带来一些速度性能提升。

答案 1 :(得分:0)

除了Dan Field的回答:

  

注2:另一个令人困惑的事情:虽然C ++消耗大约250MB的RAM,   C#需要500MB。但为什么呢?

在C ++中,你使用int,int,char(至少在32位系统上)将填充到4,4,4字节(除非结构的打包设置为1字节)。

在C#中,你使用int,double,char,它将被填充到8,8,8(或者4?)字节。填充第一个int以对齐8个字节的double。如果使用double,int,char,结构应该更小(可能是16个字节)。

虽然我不是C#专家,但我不明白为什么你在循环中使用s1[i] = new struct1();而已经有struct1的文件? (但我可能错了或遗漏了什么)。

此外,在测试数组性能时,我不会在循环中使用sqrt(),因为该函数比循环遍历项目更昂贵。

当然,在测试性能时应该启用优化。

使用循环注册甚至可以更快:

for (int i = 0; i < length; i+=4)
{
    s1[i].sampleInt = i * 2;
    s1[i].sampleDouble = i * 4;
    s1[i].sampleChar = 'c';    // reordered in order of struct
                               // not sure if it matters
    s1[i+1].sampleInt = (i+1) * 2;
    s1[i+1].sampleDouble = (i+1) * 4;
    s1[i+1].sampleChar = 'c';
                               // maybe 2 or 3 would be better than 4
    s1[i+2].sampleInt = (i+2) * 2;
    s1[i+2].sampleDouble = (i+2) * 4;
    s1[i+2].sampleChar = 'c';

    s1[i+3].sampleInt = (i+3) * 2;
    s1[i+3].sampleDouble = (i+3) * 4;
    s1[i+3].sampleChar = 'c';
}

相比
for (int i = 0; i < length; i++)
{
    s1[i].sampleChar = 'c';
    s1[i].sampleInt = i * 2;
    s1[i].sampleDouble = i * 4;
}