【问题标题】:Unsafe C# trick to improve speed提高速度的不安全 C# 技巧
【发布时间】:2011-07-15 04:49:48
【问题描述】:

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

struct MyStruct
{
    public short An1;
    public short An2;
    public short An3;
    public short An4;
}

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

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

比以下更安全的方式(例如,)的改进不是那么高(177 毫秒与 224 毫秒),但无论如何它是显着的。

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

注意:我已经剪掉了一些代码,但我认为它已经足够清晰了。

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

【问题讨论】:

  • 澄清一下,Test3 还是 Test5 更快?
  • 您是否在没有一次性 JITting 的情况下进行了测量?我的意思是您是否尝试运行一次托管函数然后循环测量它? JITting 只发生一次,因此如果将其包含在时间总和中,与不安全的方式相比将是一个糟糕的比较。
  • 为什么 AnX 方法返回一个 int?你不能让他们退回短裤并跳过演员表吗?这会提高性能吗?此外,从fixed 语句中获取指向托管缓冲区的指针似乎是一个非常糟糕的主意。我不确定,但我认为如果 GC 挡道,那可能会受到伤害。
  • @jde - 没有抖动,IL 被解释。放弃所有关于效率的假设。
  • 哦,谢谢汉斯,我不知道关于 .NET 微框架的事实......

标签: c# unsafe


【解决方案1】:

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

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

是否会修改 Test3() 以获取 ref MyStruct data 帮助?

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

【讨论】:

  • “我不认为代码不安全”...双重否定是有意的吗?
  • 谢谢克里斯。晚上写的太晚了。编辑即将到来。
  • 好主意:我没有尝试使用“ref”。另一个想法是使用“long”。我不能使用“StructLayout”,因为它在 Micro Framework 库中不可用。还是谢谢。
  • StructLayout 是微框架的一部分。 msdn.microsoft.com/en-us/library/ee434399.aspx
【解决方案2】:

看看这个example 来自另一个帖子,关于我广泛使用的一些代码。你有正确的想法,只需要设置FieldOffset()的值,然后在访问数据时使用fixed()关键字。

这种方法相当可靠,但速度并不快。我使用它的原因是,当我有很多字段时,我想以一种快速的方式将它们作为数组访问。

【讨论】:

    【解决方案3】:

    我不认为你的“技巧”有问题。没有人关心你如何索引内存,或者你使用多少偏移量来完成它。我确实认为您需要听取其他人的建议,并确保您使用 StructLayout.Sequential 或 .Explicit 控制结构的布局。还要注意尺寸和包装选项。

    已经提到的另一个问题是您需要在固定块中完成所有工作。

    fixed (byte* ptr = struct2.Buffer)
    {
        var structPtr = (MyStruct*)ptr;
        var structIndex = 0;
        do
        {
            Test5(structPtr);
        } while (++structIndex < ArraySize);
    }
    

    就个人而言,我认为您偶然发现了一些微优化剧院,使用安全的 C# 代码会更好。根据您给出的数字,(224x10^-3 - 177x10^-3) 产生 47ms,除以 5000 次迭代,每次迭代净您 9.4us (9.4x10^-6)(假设 windows 在时间)。

    【讨论】:

    • 微框架是标准框架的一个很小的子集,它是为小型设备(慢时钟,少量 ram/rom)而设计的。我展示的时间是在台式电脑上进行的(相当快),但这只是性能之间的一个指示性比率。我不能按照你的建议使用闭环,因为我的 cpu 太慢了。我想唯一合理的答案是创建一个 C++ 原生自定义驱动程序。
    • 我不知道你所说的闭环是什么意思.祝你好运。
    猜你喜欢
    • 1970-01-01
    • 2012-02-13
    • 2010-09-26
    • 2021-06-06
    • 1970-01-01
    • 2010-09-11
    • 1970-01-01
    • 2014-06-17
    • 2014-01-02
    相关资源
    最近更新 更多