2014-10-10 4 views
0

코드 NET 2.0.C#. 얼마나 빨리 바이트를 구조체에 삽입합니까?

struct에 offset 바이트를 삽입하기 위해 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 
+1

맙소사! 이 세상에서 당신은 무엇을하려고합니까? 편집 : 그것은 단지 1 구조체 유형, 안전하지 않을 것이 더 빠를 것이지만, 다음 모든 유형에 대해 동일한 코드를 구현해야 할 것입니다. – leppie

+0

그냥 프로토콜을 사용하는 가장 좋은 방법을 찾고 있습니다. – askeet

+0

내 대답 좀보세요. 정말로 속도를 원한다면 당신을 위해 일할 수도 있습니다. 조금 더 노력할 것이지만 모든 구조체 유형에 동일한 접근법을 사용할 수 있습니다. – leppie

답변

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! 
    } 
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 틱이 추가됩니다.

또한 벤치 마크 할 때 적어도 1 번의 예열을 수행해야합니다. 그래서 첫 번째 숫자가 너무 가난합니다. 내 PC에

결과 :

3312929 
4 
2 
0 
0 
0 
0 
0 
0 
0 
0 
+1

누군가가 자신의 Stopwatch.Frequency를 문서화하거나 Elapsed를 사용해야 할 것입니다. 이 숫자들은 어떤 종류의 비교도 전혀 의미가 없습니다. 80 나노 세컨드는 많은 시간이 아닙니다. –

+0

@HansPassant : 예 ... 제가 추가 할 것입니다 :) 편집 : 'Elapsed'를 사용하면 작은 테스트로 인해 무의미합니다. – leppie

+0

감사합니다. 하지만, 템플릿을 사용하는 방법 ? – askeet

관련 문제