不安全的C#伎俩来提高速度 [英] Unsafe C# trick to improve speed

查看:126
本文介绍了不安全的C#伎俩来提高速度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不习惯的指针的代码(例如C ++),也没有与不安全的岛屿:只有安全的C#。
现在我想实现对于.NET Micro Framework的,那里的紧凑性和性能是非常重要的在C#中的函数。
基本上,我会收集短裤4普莱斯,从而填补了缓冲(如字节数组)。
假设每个样本是这样的:

 结构MYSTRUCT 
{
公共短AN1 ;
公共短AN2;
公共短AN3;
公共短AN4;
}

每个样品是通过一个定时器事件收集,所以我不能环路(有几个原因)。
我尝试很多方法来有效地做到这一点,但最表演似乎是这样的:

 不安全结构MyStruct2 
{
公共固定字节的缓冲区[Program.BufferSize]
}


不安全类节目
{
公共const int的缓冲区大小= 0x1000的;
公共const int的ARRAYSIZE = BUFFERSIZE / 8;

静态MyStruct2 _struct2 =新MyStruct2();
静态MYSTRUCT * _structPtr;


不安全的静态无效的主要(字串[] args)
{
INT ITER = 5000; //只是为了模拟许多次

的for(int i = 0; I< ITER;我++)
{
//让我们一招!
固定(字节* PTR = _struct2.Buffer)
_structPtr =(MYSTRUCT *)PTR;

_structIndex = 0;

{
TEST5();
},而(++ _ structIndex< ARRAYSIZE);
}


Console.ReadKey();
}


不安全的静态无效TEST5()
{
_structPtr-> AN1 =(短)AN1();
_structPtr-> AN2 =(短)AN2();
_structPtr-> AN3 =(短)AN3();
_structPtr-> AN4 =(短)AN4();
_structPtr ++;的ADC读数
静态INT AN1()
{
返回0x1111
}


//模拟;
}

静态INT AN2()
{
返回0x2222;
}

静态INT AN3()
{
返回0x3333;
}

静态INT AN4()
{
返回0x4444;
}
}



在这个下面更安全的方式改善 - 用于例 - 没有那么高(177ms VS 224ms),但它是显著无妨。

 静态MYSTRUCT Test3的()
{
VAR数据=新MYSTRUCT();
data.An1 =(短)AN1();
data.An2 =(短)AN2();
data.An3 =(短)AN3();
data.An4 =(短)AN4();
返回数据;
}

请注意:我已经削减了一些代码,但我认为这是很清楚<。 / p>

我的问题是:绝招我已经通过复制固定指向另一个不固定可能是可靠的,或没有取得...但是你可以假定所有?该数据是静态分配的,所以应该被固定。
预先感谢您。
干杯


解决方案

我不认为代码是安全的。 _structPtr =(MYSTRUCT *)PTR 这是固定的范围内后,然后继续将数据放入_structPtr上_struct2不会移动的假设。虽然你是正确的,它不会是GCed,这并不意味着,在内存压缩GC将不会移动。 .NET Compact Framework的还是垃圾收集,我认为它压实内存而不是离开它的碎片。



如果,举例来说,一过性(非静态)对象的分配之前_struct2堆是由气相色谱然后通过该结构使用的存储器可被移位到由该瞬态对象使用的自由空间除去。在这一点上_structPtr指向未使用的内存。



会修改Test3的()取 REF MYSTRUCT数据帮助?



此外,结账 [StructLayout(LayoutKind.Explicit)] [FieldOffset( ...)] ,这将让你有在它访问相同数据的多种方式的单一结构。在你的情况无论是作为4个字节或1 int或(可能)1阵列的4个字节。


I am not used to code with pointers (e.g. C++), nor with unsafe islands: only "safe" C#. Now I'd like to implement a function in C# for the .Net Micro Framework, where the compactness and the performance are very important. Basically, I would to collect 4-ples of shorts and thus fill a buffer (e.g. byte-array). Let's say that every sample is such:

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

Each sample is collected via a timer-event, so that I can't loop (there are several reasons). I have tries many way to efficiently do that, but the most performing seems to be this one:

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

The improvement over this following safer way -for example- is not so high (177ms vs 224ms), but it is significant anyway.

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

Note: I have cut some code, but I think it's clear enough.

My question is: the "trick" I have made by copying the "fixed" pointer to another unfixed could be reliable or not?...However you can assume that all the data is statically allocated, so should be pinned. Thank you in advance. Cheers

解决方案

I don't think the code is safe. After _structPtr = (MyStruct*)ptr which is within the fixed scope, you then go on to put data into _structPtr on the assumption that _struct2 won't move. Whilst you are correct that it won't be GCed, that doesn't mean that the GC won't move it during memory compaction. The .NET Compact Framework still garbage collects, and I assume it compacts memory rather than leaving it fragmented.

If, for instance, a transient (non static) object allocated on the heap prior to _struct2 is removed by the GC then the memory in use by that struct may be shifted into the free space used by that transient object. At that point _structPtr is pointing to unused memory.

Would modifying Test3() to take a ref MyStruct data help?

Also, checkout [StructLayout(LayoutKind.Explicit)] and [FieldOffset(...)] which will allow you to have a single struct with multiple ways of accessing the same data within it. In your case either as 4 bytes or 1 int or (possibly) 1 array of 4 bytes.

这篇关于不安全的C#伎俩来提高速度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆