Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么这种循环CLI代码的性能没有明显快于C#托管代码?_C#_Performance_For Loop_C++ Cli - Fatal编程技术网

为什么这种循环CLI代码的性能没有明显快于C#托管代码?

为什么这种循环CLI代码的性能没有明显快于C#托管代码?,c#,performance,for-loop,c++-cli,C#,Performance,For Loop,C++ Cli,当我注释掉下面的大部分代码并取消注释调用CLI代码的SpeedCreateImageMap2D()行时,秒表计时实际上是相同的(两者都是5毫秒) 我希望CLI代码比托管C#快得多(例如,5x-10x),就像我过去在其他类似类型的循环函数中所经历的那样,但事实并非如此 我错过什么了吗 更新1:通过替换代码顶部,使示例最小/完整/可验证。 int width = 640; int height = 512; int numPixels = width * height; ushort[] image

当我注释掉下面的大部分代码并取消注释调用CLI代码的SpeedCreateImageMap2D()行时,秒表计时实际上是相同的(两者都是5毫秒)

我希望CLI代码比托管C#快得多(例如,5x-10x),就像我过去在其他类似类型的循环函数中所经历的那样,但事实并非如此

我错过什么了吗

更新1:通过替换代码顶部,使示例最小/完整/可验证。

int width = 640;
int height = 512;
int numPixels = width * height;
ushort[] imageData = new ushort[numPixels];
for (int i = 0; i < numPixels; i++) {
    imageData[i] = (ushort)randomGenerator.Next(4095);
}

Stopwatch sw = Stopwatch.StartNew();
// Create and populate a 2D pixel map
int rowNum, colNum;
ushort[,] pixelMap2D = new ushort[width, height];
for (int i = 0; i < numPixels; i++) {
    rowNum = i / width;
    colNum = i % width;
    pixelMap2D[colNum, rowNum] = imageData[i];
}
//ushort[,] pixelMap2D = SpeedCode.SpeedClass.SpeedCreateImageMap2D(imageData, width, height);
Debug.WriteLine("Speed(ms): " + sw.Elapsed.TotalMilliseconds.ToString("N2"));
    array<UInt16, 2> ^ SpeedClass::SpeedCreateImageMap2D(array<UInt16> ^imageData, int width, int height)
{
    // Create and populate a 2D image map from a 1D array of image data
    array<UInt16, 2> ^imageMap2D = gcnew array<UInt16, 2>(width, height);
    int k =0;
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            imageMap2D[i, j] = imageData[k];
            k++;
        }
    }
    return imageMap2D;
}
int-width=640;
整数高度=512;
int numPixels=宽度*高度;
ushort[]imageData=新的ushort[numPixels];
对于(int i=0;i
CLI功能:

array<UInt16, 2> ^ SpeedClass::SpeedCreateImageMap2D(array<UInt16> ^imageData, int width, int height)
{
    // Create and populate a 2D image map from a 1D array of image data
    array<UInt16, 2> ^imageMap2D = gcnew array<UInt16, 2>(width, height);
    int rowNum, colNum;
    int numpixels = width * height;

    for (int i = 0; i < numpixels; i++)
    {
        rowNum = i / width;
        colNum = i % width;
        imageMap2D[colNum, rowNum] = imageData[i];
    }
    return imageMap2D;
}
array^SpeedClass::SpeedCreateImageMap2D(数组^imageData,整数宽度,整数高度)
{
//从一维图像数据数组创建并填充二维图像贴图
数组^imageMap2D=gcnew数组(宽度、高度);
int rowNum,colNum;
int numpixels=宽度*高度;
对于(int i=0;i
UPDATE2:根据建议将CLI代码更改为嵌套for循环将性能提高了约2倍,但相应的托管代码性能也提高了约2倍。如果有更快的方法,请告诉我。

int width = 640;
int height = 512;
int numPixels = width * height;
ushort[] imageData = new ushort[numPixels];
for (int i = 0; i < numPixels; i++) {
    imageData[i] = (ushort)randomGenerator.Next(4095);
}

Stopwatch sw = Stopwatch.StartNew();
// Create and populate a 2D pixel map
int rowNum, colNum;
ushort[,] pixelMap2D = new ushort[width, height];
for (int i = 0; i < numPixels; i++) {
    rowNum = i / width;
    colNum = i % width;
    pixelMap2D[colNum, rowNum] = imageData[i];
}
//ushort[,] pixelMap2D = SpeedCode.SpeedClass.SpeedCreateImageMap2D(imageData, width, height);
Debug.WriteLine("Speed(ms): " + sw.Elapsed.TotalMilliseconds.ToString("N2"));
    array<UInt16, 2> ^ SpeedClass::SpeedCreateImageMap2D(array<UInt16> ^imageData, int width, int height)
{
    // Create and populate a 2D image map from a 1D array of image data
    array<UInt16, 2> ^imageMap2D = gcnew array<UInt16, 2>(width, height);
    int k =0;
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            imageMap2D[i, j] = imageData[k];
            k++;
        }
    }
    return imageMap2D;
}
array^SpeedClass::SpeedCreateImageMap2D(数组^imageData,整数宽度,整数高度)
{
//从一维图像数据数组创建并填充二维图像贴图
数组^imageMap2D=gcnew数组(宽度、高度);
int k=0;
对于(int i=0;i > 

C++和托管C++都编译到IL,而不是在运行时JIT。因此,两个版本的开销大致相同,代码本身很可能编译成非常相似的IL,因此速度上没有明显差异

从常规的C++/C代码(无需JIT)和更少的支持库中,您将获得更快的启动速度

由于更好的优化,使用C++/C可能会稍微提高代码本身的性能,但您的代码非常简单,可能会通过C#生成的代码的常规JIT生成接近最优的本机代码。或者,由于内存管理的不同折衷,本机代码可能会更慢(托管代码几乎没有时间分配和相对昂贵的取消分配,而本机代码通常平均分配成本)

我希望CLI代码比托管C#快得多(例如,5x-10x),就像我过去在其他类似类型的循环函数中所经历的那样

这非常依赖于工作负载。这还取决于您是让VC++将代码编译为IL还是本机代码

在这里,我想除法和模数控制性能。虽然其他基本操作,如
+-&| ^
非常快(如1个CPU周期延迟),但除法非常昂贵(即使在现代CPU上也是15-30个周期)。这些操作控制着吞吐量。其他一切都无关紧要。(有趣的事实:使用
%
计算bucket的哈希表要比其他方法慢得多!这个操作真的很慢。)


找到更好的方法来计算
rowNum
colNum
。两个嵌套循环是实现这一点的常用方法。

程序员往往会忽略他们可用的最有效的优化器,即他们耳朵之间的优化器。你犯了几个错误:

  • NET中的多维数组效率非常低。对它们进行索引的速度很慢,需要乘以较低的维度大小,并且对于任何元素访问都有秩数边界检查。锯齿状数组更好,索引更简单,只需一个指针+大小计算和一个边界检查
  • 您的代码以非常不利于缓存的顺序寻址数组。引用的局部性在现代处理器上非常重要,您总是希望按存储顺序寻址内存
  • C++/CLI编译器为使用有效的/clr编译的代码生成MSIL。即使是纯本地C++代码(这不是),您仍然依赖于抖动来生成和优化机器代码。在这里,C#编译器生成的MSIL类型没有任何区别。这就是为什么你无法观察到任何差异
  • 编写比抖动更快的本机代码并不是那么容易。通常,只有在故意使代码不安全时,您才会领先,例如,绕过数组索引边界检查。但是很难在这样的代码上获得回报,这里真正的节流阀是内存总线。一个不适合处理器缓存的大型阵列会导致太多的暂停,除了升级硬件之外,您别无选择
同一代码的另一个版本中有以下要点:

static array<array<UInt16>^>^ CreateImageMap2D(array<UInt16>^ imageData, int width, int height) {
    // Create and populate a 2D image map from a 1D array of image data
    auto imageMap2D = gcnew array<array<UInt16>^>(height);
    int k = 0;
    for (int i = 0; i < height; i++) {
        imageMap2D[i] = gcnew array<UInt16>(width);
        Array::Copy(imageData, k, imageMap2D[i], 0, width);
        k += width;
    }
    return imageMap2D;
}
静态数组^CreateImageMap2D(数组^imageData,整数宽度,整数高度){
//从一维图像数据数组创建并填充二维图像贴图
auto imageMap2D=gcnew数组(高度);
int k=0;
对于(int i=0;i