2013-06-30 79 views
0

我在C#應用程序中使用本機/非託管C++ DLL。我所說的本地函數來註冊使用的PInvoke在C#中的回調方法:用PInvoke回調非常慢

[DllImport("MyHook.dll", CallingConvention = CallingConvention.Cdecl)] 
[return: MarshalAs(UnmanagedType.U1)] // necessary due to http://dotnet.dzone.com/articles/pinvoke-c-bool-return-values 
private static extern bool InstallHook(CallbackPrototype callback); 

private delegate int CallbackPrototype(byte* bytes, int size, int max); 

// ... 

var callback = new CallbackPrototype(MyCallback); 
_callbackHandle = GCHandle.Alloc(callback); 
var result = InstallHook(callback); 

// somewhere when I'm removing the hook, I call _callbackHandle.Free(); 

然後,當事件發生時,本地C++ DLL調用我的回調。

private int MyCallback(byte* bytes, int size, int max) 
{ 
    //var buffer = new byte[size]; // A 
    //Marshal.Copy(new IntPtr(bytes), buffer, 0, size); // B 

    //WrapperInstance.ParseBytes(buffer, 0, size); // C 
    var x = 1 + 1; // D 

    return size; 
} 

當一切都被註釋掉,它運作良好。如果我在回調中開始取消註釋A行,它會變得很慢。我注意到了,因爲回調在關鍵時刻被調用。回調運行時間持續很長以至於我注意到它是人類是不可接受的。

這怎麼會發生? 大小參數僅從1到100.這就是最大隻需要分配100個字節 - 對於今天的計算機來說很少。我需要改進以使回調的運行時間快得多。有任何想法嗎?

爲了進一步測試,我添加了D行。這沒有任何影響。

編輯:對於更詳細的測試,我已經在類創建時分配了一個大緩衝區。所以A線不再處於回調狀態。如果B線被註釋掉,它會突然開始再次花費大量時間。這必須與託管代碼/虛擬機有關。我希望有可能讓它更快。

+1

查看代碼正在通過*移除*來減慢*昂貴的方法調用當然是完全不直觀的。很明顯,您需要停止試錯法,並通過使用分析器來收集*證據*。 –

+0

您的回調可能會被調用很多次? – ChaseMedallion

+0

它被稱爲約。一次在兩秒鐘內。 Hans Passant,如果我正確地認識你,你會誤解某些東西。當我的UNcomment行A時,這個電話會變慢。對不起,如果我弄錯了,我的英文不是很好。當我注意到我眼中的性能問題時,我無法明白爲什麼我需要使用探查器。 –

回答

1

你基本上正在做的是將字節複製到你的緩衝區,然後解析它們。你可以這樣做,在一氣呵成,就像這樣:

 var bytes = ReadBytes(address, Marshal.SizeOf(typeof(T)), isRelative); 

     fixed (byte* b = bytes) 
      return (T) Marshal.PtrToStructure(new IntPtr(b), typeof (T)); 

我已經採取了從我的記憶庫這個例子,我想這將是相當多的比你現在正在使用的代碼快,假設你只是試圖檢索值類型。