【问题标题】:Split an array composed by twisted arrays拆分由扭曲数组组成的数组
【发布时间】:2018-03-25 18:52:58
【问题描述】:

我有一个传感器,它向我发送一个一维浮点数组,我必须将其拆分为 4 个不同的子数组。我的数组代表一个框架,它由 1024 个斜坡组成。每个 Ramp 都有 4 个通道的标题和数据(我要拆分的数据)。每个通道有 2 个浮点数,一个用于实数部分,一个用于复数部分。为了澄清这一点,我附上了一张结构图:

我需要将这个大数组分解为 4 个仅包含数据的数组,每个数组用于单个通道。这必须快速完成。我的实现大约需要 850 毫秒,但遗憾的是这还不够快。到目前为止,我已经编写了下一个代码:

IntPtr ptr = (IntPtr)frameInfo.ptr; // The pointer to the buffer

for (int i = 0; i < nChannels; i++)
{
    channelFrames[i].data = new float[nRamps * nPoints * 2];
}

 for (int ramp = 0; ramp < nRamps; ramp++)
 {
     ptr += (int)rawHeaderSize; // Skip the header

     for (int point = 0; point < nPoints; point++)
     {
          for (int channel = 0; channel < nChannels; channel++)
          {
               Marshal.Copy(ptr, channelFrames[channel].data, (int)(point *2 + ramp*nPoints*2), 2);

               ptr += (sizeof(float) * 2); // Move to the next data                          
          }
     }
}

关于如何更快地做到这一点的任何想法?

【问题讨论】:

  • 也许你应该试试CodeReview
  • 您的图表似乎与您的描述或代码不匹配? “每个通道有 2 个浮点数”但您的图表显示每个通道有 8 个浮点数?什么是点,什么是 nPoints?你为什么要一次复制 2 个浮点数(根据你的图表,这将是 re0+re1 然后是 re2+re3)?我假设datafloat Array,因为您为其分配了new float[]
  • @NetMage 不,它显示每个通道 2 个浮点数。每个浮点数为 4 个字节,因此 Re0Re1Re2Re3 生成一个浮点数,Im0Im1Im2Im3 生成另一个浮点数。 nPoints 是 4096。 Marshal.Copy 已经将 4 个字节更改为浮点数。我需要将浮点数、实部和虚部都复制到通道数组中。
  • 我明白了——每个代表一个字节。

标签: c# .net arrays performance


【解决方案1】:

Marshal.Copy() 可能是性能瓶颈,因为它调用了非托管代码,而且这个调用太昂贵,不能只复制 2 个浮点数。以下使用不安全代码(必须在项目属性中启用,方法必须用unsafe修饰符修饰)以避免使用Marshal.Copy()并手动复制数据。内部循环(迭代通道)也被展开,以获得一些额外的性能增益(这样做的缺点是代码被硬编码为 4 个通道)。

我的测量结果显示,与原始方法相比,性能提升了近 10 倍。

//Pin arrays with channel data in memory and get pointers of these fixed arrays
fixed (float* fixed_ch0ptr = channelFrames[0].data)
fixed (float* fixed_ch1ptr = channelFrames[1].data)
fixed (float* fixed_ch2ptr = channelFrames[2].data)
fixed (float* fixed_ch3ptr = channelFrames[3].data)
{
    //fixed arrays pointer cannot be modified, we must create writable copies ot these pointers
    float* ch0ptr = fixed_ch0ptr;
    float* ch1ptr = fixed_ch1ptr;
    float* ch2ptr = fixed_ch2ptr;
    float* ch3ptr = fixed_ch3ptr;

    //unsafe pointer to array from sensor
    float* floatptr = (float*)ptr;

    for (int ramp = 0; ramp < nRamps; ramp++)
    {
        floatptr = (float*)((byte*)(floatptr) + (int)rawHeaderSize); // Skip the header

        for (int point = 0; point < nPoints; point++)
        {
            //Unrolling loop that iterates over channelFrames can give as some additional performance gains

            //copy channel 0 data
            *ch0ptr++ = *(floatptr++);
            *ch0ptr++ = *(floatptr++);

            //copy channel 1 data
            *ch1ptr++ = *(floatptr++);
            *ch1ptr++ = *(floatptr++);

            //copy channel 2 data
            *ch2ptr++ = *(floatptr++);
            *ch2ptr++ = *(floatptr++);

            //copy channel 3 data
            *ch3ptr++ = *(floatptr++);
            *ch3ptr++ = *(floatptr++);
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-07
    • 2021-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-19
    • 2011-02-21
    相关资源
    最近更新 更多