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

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

我想念什么吗?

UPDATE1:通过替换代码的顶部,使示例变得最小/完整/可验证。

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"));

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;
}

UPDATE2:根据建议将CLI代码更改为嵌套的for循环可将性能提高约2倍,但相应的托管代码性能也可提高约2倍。 如果有更快的方法可以进行此操作,请告诉我。

    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;
}

#1楼 票数:4 已采纳

程序员往往会忽略他们现有的最有效的优化器,即他们的耳朵之间的优化器。 您正在犯几个错误:

  • .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;
}

我没有测量它,但是您应该在更好的缓存利用率方面处于领先地位。 进一步优化此代码不太可能获得回报,您需要击败Array :: Copy()。 它已经优化。 但是你可以用尝试pin_ptr<>针脚阵列和memcpy()来复制数据。 用C#编写此代码不会产生任何变化,可能就是您想要做的。

#2楼 票数:0

C#和托管C ++都可以编译为IL,然后在运行时编译。 结果,这两个版本的开销大约相同,并且代码本身很可能被编译为非常相似的IL-因此,速度的预期不会有显着差异。

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

由于进行了更好的优化,使用C ++ / C 可能会使代码本身的性能稍好一些,但是您的代码非常简单,并可能通过C#生成的代码的常规JIT生成接近最佳的本机代码。 或者,由于内存管理的权衡取舍,本地代码可能会变慢(托管代码几乎没有时间分配,并且分配的开销相对较高,而本地代码通常会平均分配成本)。

#3楼 票数:0

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

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

在这里,我猜想除法和模量会主导性能。 尽管其他基本操作(例如+-&|^非常快(例如1个CPU周期延迟),但除法的确非常昂贵(即使在现代CPU上也需要15-30个周期)。 这些操作控制吞吐量。 其他一切都没有多大关系。 (有趣的事实:使用%来计算存储桶的哈希表比替代方法要慢得多!该操作确实很慢。)

找到一种更好的方法来计算rowNumcolNum 两个嵌套循环是执行此操作的常用方法。

  ask by nb1forxp translate from so

未解决问题?本站智能推荐:

3回复

与Native C ++相比,C ++ / CLI性能如何?

早上好, 我正在编写一个拼写检查程序,对于这种情况,它是性能关键的。 既然如此,由于我计划连接到数据库并使用C#创建GUI,我在C中编写了一个编辑距离计算例程,并编译为我在C#中使用DllImport的DLL。 问题是我认为 (虽然我可能错了)从String到char *逐个编组单词会
1回复

C ++ / CLI + C ++ Native会提高性能吗? [关闭]

在我们的项目中,我们有三个模块。 C ++(Native),C ++ / CLI,C#。 我们使用C ++ / CLI在C#中使用C ++(Native)代码。 为此我们静态地将C ++(Native)与C ++ / CLI连接起来,现在我们可以使用C ++ / C ++管理的dll。
5回复

用于在Windows上创建快速,现代和响应式GUI的C ++ / CLI或C#[关闭]

目前我分为这两种语言。 我差不多编程了当前的应用程序,需要非常快。 它可以在多种负载条件下计算任何类型的绝缘玻璃结构。 我只是不知道它是否是用C ++ / CLI编写它的正确选择。 例如,在互联网上,我甚至从未读过“C ++ / CLI”的名称,但每个人都建议学习C#。 C +
2回复

C#编译器输出与C ++ / CLI编译器的区别

我有一个WPF应用程序,可以在大型数据集中进行大量匹配,目前它使用C#和LINQ来匹配POCO并在网格中显示。 随着所包含数据集的数量增加,数据量增加,我被要求查看性能问题。 我今天晚上测试的一个假设是,如果我们将一些代码转换为C ++ CLI,是否存在实质性差异。 为此,我编写了一个简单
3回复

包含char数组时快速读取C结构

我有以下C结构 我现在有一堆用C创建的文件,其中包含数千种结构。 我需要使用C#阅读它们,速度是一个问题。 我已经在C#中完成了以下操作 然后我使用以下命令从文件中读取数据 这非常有效,我可以从文件中检索数据。 我已经读过,如果我不使用GCHandle.Al
2回复

C#与C ++进行循环性能测量

对于踢球,我想看看C#for循环的速度与C ++ for循环的速度相比。 我的测试是简单地遍历一个for循环100000次,100000次并取平均结果。 这是我的C#实现: 结果: Average runtime = 10301.92929 ms. 这是我的C ++实现:
1回复

forEach函数比等效的for循环快得多

在我正在构建的Angular应用中,我有两段代码每次刷新都会触发。 它们都执行相同的操作,但是速度更快的是forEach函数数组,我认为应该稍微慢一点 。 如果发现错误,那就太好了! 但是为什么foreach循环会这么快。 它们彼此紧紧相接,如果我改变顺序,那也没有什么不同。
2回复

Double for循环的代码性能与linq / lambda相比

我喜欢linq / lambda语句的外观,并想知道它的性能 与此相比: 仍然不熟悉人们如何用O(nlogn)来描述性能,但是通过与此类聊天的持续交互,我了解到双循环通常会给出O(n ^ 2)