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

Posted

技术标签:

【中文标题】提高速度的不安全 C# 技巧【英文标题】:Unsafe C# trick to improve speed 【发布时间】: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 微框架的事实...... 【参考方案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++ 原生自定义驱动程序。 我不知道你所说的闭环是什么意思.祝你好运。

以上是关于提高速度的不安全 C# 技巧的主要内容,如果未能解决你的问题,请参考以下文章

C#一些小技巧

C# 中的不安全代码

微信小程序之提高应用速度小技巧

高速pcb布线技巧

网站打开速度优化_如何提高网页访问速度技巧方法总结

Java 线程安全