Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.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
昂贵的C#操作,希望提高性能_C#_Performance_Parallel Processing - Fatal编程技术网

昂贵的C#操作,希望提高性能

昂贵的C#操作,希望提高性能,c#,performance,parallel-processing,C#,Performance,Parallel Processing,这将是一个很长的问题,请提前道歉。我并不期待一个完整的代码解决方案,我正在寻找一些来自不同视角和比我更有经验的人的意见 我的公司正在为一种产品开发软件,该产品使用红外相机的胶片进行一些相当昂贵的计算,其中每个像素都包含一个温度值。这些方法中成本最高的称为热信号重建(如果您感兴趣,可以在这里阅读)。它基本上对每个像素随时间(帧数)进行多项式拟合。我的C#实现如下所示: public static double[] PolynomialRegression(in double[] xValu

这将是一个很长的问题,请提前道歉。我并不期待一个完整的代码解决方案,我正在寻找一些来自不同视角和比我更有经验的人的意见

我的公司正在为一种产品开发软件,该产品使用红外相机的胶片进行一些相当昂贵的计算,其中每个像素都包含一个温度值。这些方法中成本最高的称为热信号重建(如果您感兴趣,可以在这里阅读)。它基本上对每个像素随时间(帧数)进行多项式拟合。我的C#实现如下所示:

    public static double[] PolynomialRegression(in double[] xValues, in double[] yValues, byte order)
    {
      Debug.Assert(xValues != null && yValues != null);
      Debug.Assert(xValues.Length == yValues.Length);
      Debug.Assert(xValues.Length != 0 || yValues.Length != 0);

      int dataSamples = xValues.Length;
      double[] result = new double[order + 1];

      // array containing N,sigma(xi),sigma(xi^2),sigma(xi^3)...sigma(xi^2*poly_order), where N=number of samples
      double[] sigmaX = new double[2 * order + 1];
      for (var index = 0U; index < sigmaX.Length; ++index)
      {
        sigmaX[index] = 0.0;
        for (var dataPoint = 0U; dataPoint < dataSamples; ++dataPoint)
          sigmaX[index] += System.Math.Pow(xValues[(int)dataPoint], index);
      }

      // array containing sigma(yi),sigma(xi*yi),sigma(xi^2*yi)...sigma(xi^poly_order*yi)
      double[] sigmaY = new double[order + 1];
      for (var pOrder = 0U; pOrder < sigmaY.Length; ++pOrder)
      {
        sigmaY[pOrder] = 0.0;
        for (var dataPoint = 0U; dataPoint < dataSamples; ++dataPoint)
          sigmaY[pOrder] += System.Math.Pow(xValues[(int)dataPoint], pOrder) * yValues[(int)dataPoint];
      }

      // equation system's augmented normal matrix
      int matrixRows = order + 1;
      int matrixCols = order + 2;
      double[,] matrix = new double[matrixRows, matrixCols];
      for (var row = 0U; row < matrixRows; ++row)
        for (var col = 0U; col < matrixCols - 1; ++col)
          matrix[row, col] = sigmaX[row + col];
      for (var row = 0U; row < matrixRows; ++row)
        matrix[row, order + 1] = sigmaY[row];

      // pivotisation of matrix
      for (var pivotRow = 0U; pivotRow < matrixRows; ++pivotRow)
        for (var lowerRow = pivotRow + 1U; lowerRow < matrixRows; ++lowerRow)
          if (matrix[pivotRow, pivotRow] < matrix[lowerRow, pivotRow])
            for (var col = 0U; col < matrixCols; ++col)
            {
              double temp = matrix[pivotRow, col];
              matrix[pivotRow, col] = matrix[lowerRow, col];
              matrix[lowerRow, col] = temp;
            }

      // Gaussian elimination
      for (var pivotRow = 0U; pivotRow < matrixRows; ++pivotRow)
        for (var lowerRow = pivotRow + 1U; lowerRow < matrixRows; ++lowerRow)
        {
          double ratio = matrix[lowerRow, pivotRow] / matrix[pivotRow, pivotRow];
          for (var col = 0U; col < matrixCols; ++col)
            matrix[lowerRow, col] -= ratio * matrix[pivotRow, col];
        }

      // back-substitution
      for (var row = (short)order; row >= 0; --row)
      {
        result[row] = matrix[row, order + 1];
        for (var col = 0U; col < matrixCols - 1; ++col)
          if (col != row)
            result[row] -= matrix[row, col] * result[col];
        result[row] /= matrix[row, row];
      }

      return result;
    }
publicstaticdouble[,,]热信号重构(列表热信号,字节多序)
{
分辨率胶片分辨率=热胶片[0]。分辨率;
uint宽度=胶片分辨率。宽度;
uint高度=胶片分辨率。高度;
int frames=热胶片计数;
双精度[,]结果=新双精度[polyOrder+1,高度,宽度];
//使用帧索引作为多边形拟合的x值
列表框架索引=新列表(框架);
用于(可变帧=0U;帧<帧;+帧)
frameindex.Add(frame);
//制作热膜的局部副本,并用差异图像填充
List localThermalFilm=新列表(帧);
用于(可变帧=0U;帧<帧;+帧)
添加(新帧(胶片分辨率));
并行。对于(0U,帧,帧=>
{
用于(变量行=0U;行<高度;++行)
用于(变量列=0U;列<宽度;++列)
localThermalFilm[(int)frame]。数据[行,列]=thermalFilm[(int)frame]。数据[行,列]-thermalFilm[0]。数据[行,列];
});
//通过查找具有最大平均像素值的帧来确定闪点
double maxAverage=double.MinValue;
uint最大索引=0U;
并行。对于(0U,帧,帧=>
{
双平均=Math.MatrixMean(localThermalFilm[(int)frame].Data);
如果(平均值>最大平均值)
{
最大平均值=平均值;
maxIndex=(uint)帧;
}
});
//从胶片上移除闪点之前的框架,包括其本身
localThermalFilm.RemoveRange(0,(int)maxIndex+1);
frameIndexes.RemoveRange(0,(int)maxIndex+1);
帧-=(int)最大索引+1;
//计算所有像素和帧索引的以10为底的对数
并行。对于(0U,帧,帧=>
{
用于(变量行=0U;行<高度;++行)
用于(变量列=0U;列<宽度;++列)
localThermalFilm[(int)frame]。数据[行,列]=System.Math.Log10(localThermalFilm[(int)frame]。数据[行,列];
frameIndexes[(int)frame]=System.Math.Log10(frameIndexes[(int)frame]);
});
//对每个像素执行多项式拟合
平行。对于(0U,高度,行=>
{
用于(变量列=0U;列<宽度;++列)
{
//提取当前像素的多边形拟合输入y值
double[]像素值=新的双[帧];
用于(可变帧=0U;帧<帧;+帧)
像素值[frame]=localThermalFilm[(int)frame]。数据[row,col];
//(…)执行一些值验证
//适合当前像素的多边形-这是最长的一步
double[]系数=数学多项式回归(FrameIndexValidated.ToArray(),pixelValuesValidated.ToArray(),polyOrder);
//插入到系数图像结果数组中
对于(var系数=0U;系数
如您所见,在帧上执行多个操作的几个并行循环是按顺序执行的,多项式拟合(Math.PolynomialRegression)是最后一个也是最昂贵的。这是一个包含多项式拟合算法的函数,我自己拼凑的,因为它在标准系统中不存在。Math library和我在Math.NET library中尝试的唯一一个函数实际上比我编写的运行得慢。我的代码基于Rosetta代码中给出的示例:

我的观点是,我以前在非托管C++中写了整个算法,我们公司决定远离这个问题,因为我们使用的GUI框架有一些许可问题,现在使用C.Y./.NET。一个直接的比较旧的非托管C++代码和上面在托管C语言中发布的代码,显示了C代码比C++代码要长48%(!!),即使算法是相同的。我知道C++是一种高级的、管理的语言,因此比C++有更大的翻译距离,所以我完全希望它运行得慢一些,但我没想到它会这么糟糕。48%是一件大事,这让我相信我可能做错了什么。另一方面,我还没有太多的经验,所以如果我非常诚实的话,我也不知道在这种情况下会发生什么

到目前为止,我所尝试的:

  • 在顺序运行各个循环和并行运行之间切换,所有循环都像上面那样并行运行,速度最快
  • 调整单个并行化循环实例访问的变量(例如,每次不访问相同的分辨率对象,但在开始循环之前声明单独的宽度和高度变量),这已经大大提高了性能,但之后仍保留了48%
  • 尝试Parallel.ForEach(Partitioner.Create(0,frames)…)方法,即使用Partitioner类对数据块进行更粗略的分区,这没有帮助,会使代码运行变慢
  • 尽可能优化调用的其他函数以及调用方的代码
问题是:是否有可能使这样的C代码与C++中的相同代码运行性能相当,如果是这样的话,怎么办?还是我观察到的完全正常,我必须处理


编辑:在TSR中为每个请求和我的多项式回归添加前三个循环体
    public static double UIntPow(double @base, uint power)
    {
      if (power == 0)
        return 1.0;
      else if (power == 1)
        return @base;
      else
        return @base * UIntPow(@base, power - 1);
    }
    public static double UIntPow(double @base, uint power)
    {
      double result = 1.0;
      while (power != 0)
      {
        if ((power & 1) == 1)
          result *= @base;
        @base *= @base;
        power >>= 1;
      }
      return result;
    }