不安全的C#技巧提高速度

Mar*_*ari 13 c# unsafe

我不习惯用指针代码(例如C++),也有不安全的岛屿:只有"安全"的C#.现在我想在.Net Micro Framework的C#中实现一个函数,其中紧凑性和性能非常重要.基本上,我会收集4个短裤,从而填充缓冲区(例如字节数组).让我们说每个样本都是这样的:

struct MyStruct
{
    public short An1;
    public short An2;
    public short An3;
    public short An4;
}
Run Code Online (Sandbox Code Playgroud)

每个样本都是通过计时器事件收集的,因此我无法循环(有几个原因).我已经尝试了很多方法来有效地做到这一点,但表现最好的似乎是这一个:

unsafe struct MyStruct2
{
    public fixed byte Buffer[Program.BufferSize];
}


unsafe class Program
{
    public const int BufferSize = 0x1000;
    public const int ArraySize = BufferSize / 8;

    static MyStruct2 _struct2 = new MyStruct2();
    static MyStruct* _structPtr;


    unsafe static void Main(string[] args)
    {
        int iter = 5000;  //just for simulate many cycles

        for (int i = 0; i < iter; i++)
        {
            //let's make a trick!
            fixed (byte* ptr = _struct2.Buffer)
                _structPtr = (MyStruct*)ptr;

            _structIndex = 0;
            do
            {
                Test5();
            } while (++_structIndex < ArraySize);
        }


        Console.ReadKey();
    }


    unsafe static void Test5()
    {
        _structPtr->An1 = (short)An1();
        _structPtr->An2 = (short)An2();
        _structPtr->An3 = (short)An3();
        _structPtr->An4 = (short)An4();
        _structPtr++;
    }


    //simulations of ADC reading
    static int An1()
    {
        return 0x1111;
    }

    static int An2()
    {
        return 0x2222;
    }

    static int An3()
    {
        return 0x3333;
    }

    static int An4()
    {
        return 0x4444;
    }
}
Run Code Online (Sandbox Code Playgroud)

对以下更安全的方式的改进 - 例如 - 不是那么高(177ms对224ms),但无论如何它都很重要.

    static MyStruct Test3()
    {
        var data = new MyStruct();
        data.An1 = (short)An1();
        data.An2 = (short)An2();
        data.An3 = (short)An3();
        data.An4 = (short)An4();
        return data;
    }
Run Code Online (Sandbox Code Playgroud)

注意:我已经删除了一些代码,但我认为它已经足够清楚了.

我的问题是:我通过将"固定"指针复制到另一个未固定的"技巧"可能是否可靠?...但是你可以假设所有数据都是静态分配的,所以应该固定.先感谢您.干杯

Jos*_*her 1

我认为该代码不安全。在固定范围内之后_structPtr = (MyStruct*)ptr,您可以假设 _struct2 不会移动,然后继续将数据放入 _structPtr 中。虽然您认为它不会被 GC 是正确的,但这并不意味着 GC 在内存压缩期间不会移动它。.NET Compact Framework 仍然进行垃圾收集,我认为它会压缩内存而不是使其碎片化。

例如,如果在 _struct2 之前在堆上分配的瞬态(非静态)对象被 GC 删除,则该结构使用的内存可能会转移到该瞬态对象使用的空闲空间中。此时 _structPtr 指向未使用的内存。

修改 Test3() 会有帮助吗ref MyStruct data

此外,签出[StructLayout(LayoutKind.Explicit)][FieldOffset(...)]它将允许您拥有一个具有多种访问其中相同数据的方式的结构。在您的情况下,可以是 4 个字节或 1 个 int 或(可能)1 个 4 字节数组。