C++ 数组 vs C# ptr 速度混淆
Posted
技术标签:
【中文标题】C++ 数组 vs C# ptr 速度混淆【英文标题】:C++ array vs C# ptr speed confusion 【发布时间】:2016-06-09 12:31:11 【问题描述】:我正在将高性能 C++ 应用程序重写为 C#。 C# 应用程序明显比 C++ 原始应用程序慢。分析告诉我 C# 应用程序花费大部分时间来访问数组元素。因此,我创建了一个简单的数组访问基准。我得到的结果与others doing a similiar comparison 完全不同。
C++ 代码:
#include <limits>
#include <stdio.h>
#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int main(void)
high_resolution_clock::time_point t1 = high_resolution_clock::now();
int xRepLen = 100 * 1000;
int xRepCount = 1000;
unsigned short * xArray = new unsigned short[xRepLen];
for (int xIdx = 0; xIdx < xRepLen; xIdx++)
xArray[xIdx] = xIdx % USHRT_MAX;
int * xResults = new int[xRepLen];
for (int xRepIdx = 0; xRepIdx < xRepCount; xRepIdx++)
// in each repetition, find the first value, that surpasses xArray[xIdx] + 25 - i.e. we will perform 25 searches
for (int xIdx = 0; xIdx < xRepLen; xIdx++)
unsigned short xValToBreach = (xArray[xIdx] + 25) % USHRT_MAX;
xResults[xIdx] = 0;
for (int xIdx2 = xIdx + 1; xIdx2 < xRepLen; xIdx2++)
if (xArray[xIdx2] >= xValToBreach)
xResults[xIdx] = xIdx2; break;
if (xResults[xIdx] == 0)
xResults[xIdx] = INT_MAX;
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto duration = duration_cast<milliseconds>(t2 - t1).count();
cout << "Elasped miliseconds " << duration;
getchar();
C# 代码:
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace arrayBenchmarkCs
class Program
public static void benchCs()
unsafe
int xRepLen = 100 * 1000;
int xRepCount = 1000;
ushort[] xArr = new ushort[xRepLen];
for (int xIdx = 0; xIdx < xRepLen; xIdx++)
xArr[xIdx] = (ushort)(xIdx % 0xffff);
int[] xResults = new int[xRepLen];
Stopwatch xSw = new Stopwatch(); xSw.Start();
fixed (ushort * xArrayStart = & xArr [0])
for (int xRepIdx = 0; xRepIdx < xRepCount; xRepIdx++)
// in each repetition, go find the first value, that surpasses xArray[xIdx] + 25 - i.e. we will perform 25 searches
ushort * xArrayEnd = xArrayStart + xRepLen;
for (ushort* xPtr = xArrayStart; xPtr != xArrayEnd; xPtr++)
ushort xValToBreach = (ushort)((*xPtr + 25) % 0xffff);
int xResult = -1;
for (ushort * xPtr2 = xPtr + 1; xPtr2 != xArrayEnd; xPtr2++)
if ( *xPtr2 >= xValToBreach)
xResult = (int)(xPtr2 - xArrayStart);
break;
if (xResult == -1)
xResult = int.MaxValue;
// save result
xResults[xPtr - xArrayStart] = xResult;
// fixed
xSw.Stop();
Console.WriteLine("Elapsed miliseconds: " + (xSw.ElapsedMilliseconds.ToString("0"));
static void Main(string[] args)
benchCs();
Console.ReadKey();
在我的工作计算机 (i7-3770) 上,C++ 版本比 C# 版本快大约 2 倍。在我的家用计算机 (i7-5820K) 上,C++ 比 C# 版本快 1.5 倍。两者都在 Release 中测量。我希望通过在 C# 中使用指针可以避免数组边界检查,并且两种语言的性能相同。
所以我的问题如下:
其他人发现 C# 的速度与 C++ 相同? 如果不通过指针,如何将 C# 性能提升到 C++ 级别? 不同计算机上不同加速的驱动因素可能是什么?非常感谢任何提示, 丹尼尔
【问题讨论】:
我希望您在没有调试器的情况下执行基准测试(在 Visual Studio 中使用 CTRL+F5 而不是 F5) @xanatos:是的。不过感谢您的快捷方式。 ushort * xArrayEnd = xArrayStart + xRepLen; 你可以把它移到for
循环之外
@xanatos:确实,性能差异保持不变。
您链接的基准测试的作者看起来偏向于 C# 而不是 C++。再加上他不共享基准代码的事实看起来很可疑……最后,std::vector::operator[]()
不检查边界。 std::vector::at()
确实,他一直都错了。
【参考方案1】:
你不会得到这种以 C++ 速度计算的核心数字。使用指针算术和不安全代码可以帮助您解决问题(如果您删除不安全和固定部分,速度几乎是原来的一半)。 C# 没有编译为本机代码,它运行的代码充满了额外的检查和东西。
如果您愿意使用unsafe
,那么真的没有什么能阻止您将 C++ 性能关键的东西编码到混合模式程序集中,并从 C# 胶水代码中调用它。
【讨论】:
感谢您为我指明方向。我读过的(少量)文章指出,运行时从托管代码切换到非托管代码并返回很慢。你的经历真的是这样吗? 不是说一次做需要很长时间,而是循环做很多次就不好了。理想情况下,您在 C# 中准备好所有内容,然后将所有内容交给 C++,它可以完成所有循环和数学运算。然后它将这些结果打包备份,您可以返回托管世界的所有好处,并快速完成您的计算。【参考方案2】:C++ 代码的工作方式与 C# 不同。内循环不同。 xResults[xIdx] 有 4 个内存操作,而 c# 中只有 1 个。
我很震惊,C# 代码的性能如此依赖于框架版本。 更有趣的是,.net core 3.1 上的 C# 比 C++ 高出 5%。使用其他框架,我检查了 C# 比 C++ 慢 30-50%
【讨论】:
您是否使用问题中的相同代码?你试过不同的长度吗?你能展示一些详细的结果吗? 不,我必须更改 C++ 代码才能像 c# 一样工作。我没有尝试不同的长度,但我尝试了更多的重复 - 结果相同。 更改片段:for (unsigned short* xPtr = xArray; xPtr != xArrayEnd; ++xPtr)
` unsigned short xValToBreach = (xPtr + 25) % USHRT_MAX;` xResult = -1; ` for (unsigned short xPtr2 = xPtr + 1; xPtr2 != xArrayEnd; ++xPtr2)` ` if (*xPtr2 >= xValToBreach)` ` ` ` xResult = (int)(xPtr2 - xArray); break;` ` ` ` if (xResult == -1)` ` xResult = INT_MAX;` ` xResults[xPtr - xArray] = xResult;` ` ` ` `以上是关于C++ 数组 vs C# ptr 速度混淆的主要内容,如果未能解决你的问题,请参考以下文章