C#。什么时候将Byte插入Struct的速度有多快?

时间:2014-10-10 07:29:41

标签: c# .net serialization struct marshalling

NET 2.0代码。

我在struct中编写函数ByteArrayToObject用于插入偏移字节,但是可以快速吗? 计划有很多结构需要附加更改的网络信息。如果我可以将这些字节快速插入到正确的位置,它将作为一个大结构在协议中组织。 感谢您的任何帮助。

在我的情况下,我不喜欢每次都要替换必须执行对象func ObjectToByteArray的所有副本的字节。

 /// <summary> Convert an object struct to a byte array </summary>
        private static byte[] ObjectToByteArray(Object obj)
        {

            var size = Marshal.SizeOf(obj);
            // Both managed and unmanaged buffers required.
            var bytes = new byte[size];
            var ptr = Marshal.AllocHGlobal(size);
            // Copy object byte-to-byte to unmanaged memory.
            Marshal.StructureToPtr(obj, ptr, false);
            // Copy data from unmanaged memory to managed buffer.
            Marshal.Copy(ptr, bytes, 0, size);
            // Release unmanaged memory.
            Marshal.FreeHGlobal(ptr);
            return bytes;
        }

        /// <summary>  Need Faster ? </summary>
        public static T ByteArrayToObject<T>(ref T obj,  int StartOffset, params byte[] bytes) 
        {
            int size = Marshal.SizeOf(obj);
            int Length = (bytes.Length > size) ? size : bytes.Length;
            byte[] Allbytes = ObjectToByteArray(obj);
            Array.Copy(bytes, 0, Allbytes, StartOffset, Length - StartOffset);
            var ptr = Marshal.AllocHGlobal(size);
            Marshal.Copy(Allbytes, 0, ptr, Length );
            obj = (T)Marshal.PtrToStructure(ptr, typeof(T));
            Marshal.FreeHGlobal(ptr);
            return obj;
        }

使用示例

    [Serializable]
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
    struct Protocol
    {
        public byte f0;
        public byte f1;
        public short f2;
        public byte f3;
        public long f4;            
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 20000)] 
        public int[] Array; // 20000

        }

       System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
       for (byte i = 1; i < 10; i++)
       {
           sw.Reset();
           sw.Start();
           ob = ByteArrayToObject<Protocol>(ref ob,1, i, 0x11, i, 0x22, i);
           sw.Stop();
           Console.WriteLine("Tick =" + sw.ElapsedTicks);
       }

输出

Tick =9940
Tick =686
Tick =593
Tick =474
Tick =562
Tick =5283
Tick =193
Tick =173
Tick =164

2 个答案:

答案 0 :(得分:1)

这对评论来说太长了,但要扩展不安全的方法:

unsafe struct Ex
{
  public byte f0,f1,f2,f3,f4;
  public fixed int buffer[20000];
}

class Program
{
  public static unsafe void ByteArrayToEx(Ex* obj, int offset, params byte[] bytes)
  { 
    // you should add some safely nets here sizeof(Ex) should used for size of struct
    byte* p = (byte*)obj;
    foreach (var b in bytes)
    {
      p[offset++] = b;
    }
    // dont return value, it is expensive!
  }

  unsafe static void Main(string[] args)
  {
    Stopwatch sw = new Stopwatch();
    Console.WriteLine(Stopwatch.Frequency);
    Ex e = new Ex { f0 = 0, f1 = 1, f2 = 2, f3 = 3, f4 = 4 };
    ByteArrayToEx(&e, 2, 5, 6, 7);
    for (int i = 0; i < 10; i++) {
      sw.Restart();
      ByteArrayToEx(&e, 2, (byte) i, 6, 7);
      sw.Stop();
      Console.WriteLine(sw.ElapsedTicks);
    }
  }
}

这可能适用于您,也可能不适合您。也不要返回值。您已经在改变指向它的指针。返回这样一个大结构的副本会为每次调用添加10个滴答。

此外,在替补标记时,您需要至少进行一次预热。这就是为什么第一个数字太差了。

我的电脑上的结果:

3312929
4
2
0
0
0
0
0
0
0
0

答案 1 :(得分:0)

重写了一点

    public static unsafe void ByteArrayToEx(ref Ex  value, int offset, params byte[] bytes)
    {
        // you should add some safely nets here sizeof(Ex) should used for size of struct

        fixed (Ex* obj = &value)
        {
            byte* p = (byte*)obj;
            foreach (var b in bytes)
            {
                p[offset++] = b;
            }
        }
        // dont return value, it is expensive!
    }