Raw Binary Value Serializer

  • VB.NET

Es gibt 23 Antworten in diesem Thema. Der letzte Beitrag () ist von Bluespide.

    Um mehr Performance raus zu hohlen habe ich das nochmal umgeschrieben und in eine Extension verpackt. Mit "GCHandle.Alloc" auf ein Managed Byte Array schreibe ich jetzt 100 Mio. Strukturen anstatt 1 Mio. innerhalb von 1,2 Sekunden. Warum das schneller ist, weiß ich nicht. Ich brauche das eigentlich auch nicht, das reicht so schon vollkommen, aber es macht auch irgendwie Spaß daran zu basteln. :)

    C#-Quellcode

    1. public static byte[] RawSerialize<T>(this T item) where T : struct {
    2. byte[] buffer = new byte[Marshal.SizeOf(typeof(T))];
    3. GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
    4. Marshal.StructureToPtr(item, handle.AddrOfPinnedObject(), false);
    5. handle.Free();
    6. return buffer;
    7. }
    8. public static T RawDeserialize<T>(this byte[] rawData) where T : struct {
    9. GCHandle handle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
    10. T str = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
    11. handle.Free();
    12. return str;
    13. }
    GCHandle.Alloc macht genau das gleiche, wie fixed. Mit fixed kannst du aber halt keine generischen Typen anpinnen, mit GCHandle schon. Ich halte es übrigens so, dass das GCHandle IMMER freigegeben wird, also in einem Try-Finally-Block.

    C#-Quellcode

    1. var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
    2. try
    3. {
    4. //...
    5. }
    6. finally
    7. {
    8. handle.Free();
    9. }


    Das Anlegen von Speicher über bspw. AllocHGlobal (für das das gleiche gilt: Wieder freigeben in einem Try-Finally-Block, wobei das hier sogar "wichtiger" scheint. Es entstehen sonst Speicherlecks, sofern ein Fehler auftritt - woher auch immer dieser kommen soll) ist recht ineffizient.
    In der RawDeserialize-Methode kannst du übrigens das fixed-Statement verwenden, da es keine generische Typdefinition ist:

    C#-Quellcode

    1. fixed(byte* ptr = rawData)
    2. {
    3. return Marshal.PtrToStructure<T>(ptr);
    4. }


    Viele Grüße
    ~blaze~
    Achso ok, also:

    C#-Quellcode

    1. public static byte[] RawSerialize<T>(this T item) where T : struct {
    2. byte[] buffer = new byte[Marshal.SizeOf(typeof(T))];
    3. GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
    4. try {
    5. Marshal.StructureToPtr(item, handle.AddrOfPinnedObject(), false);
    6. return buffer;
    7. } finally {
    8. handle.Free();
    9. }
    10. }
    11. public static T RawDeserialize<T>(this byte[] rawData) where T : struct {
    12. GCHandle handle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
    13. try {
    14. T item = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
    15. return item;
    16. } finally {
    17. handle.Free();
    18. }
    19. }


    und für unsafe das nochmal schnellere:

    C#-Quellcode

    1. public static unsafe byte[] RawSerialize<T>(this T item) where T : struct {
    2. byte[] buffer = new byte[Marshal.SizeOf(typeof(T))];
    3. fixed (byte* ptr = buffer) {
    4. Marshal.StructureToPtr(item, new IntPtr(ptr), false);
    5. }
    6. return buffer;
    7. }
    8. public static unsafe T RawDeserialize<T>(this byte[] rawData) where T : struct {
    9. fixed (byte* ptr = rawData) {
    10. return Marshal.PtrToStructure<T>(new IntPtr(ptr));
    11. }
    12. }