使用PInvoke进行回调非常慢

时间:2013-06-30 13:39:54

标签: c# c++ callback pinvoke unmanaged

我在C#应用程序中使用本机/非托管C ++ DLL。我调用一个本机函数来使用PInvoke在C#中注册一个回调方法:

[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行,它会变得很慢。我注意到它是因为在关键时刻调用了回调。回调运行时间很长,以至于我注意到它是一个人类,这是不可接受的。

怎么会发生这种情况? size 参数只有1到100.最多只需要分配100个字节 - 对于今天的计算机来说非常少。我需要改进以使回调的运行时间更快。有什么想法吗?

为了进一步测试,我添加了D行。这没有任何影响。

编辑:对于更详细的测试,我在创建类时分配了一个大缓冲区。所以A行不再在回调中了。如果B行被注释掉,它会突然又开始耗费大量时间。这必须与托管代码/虚拟机有关。我希望有可能让它更快。

1 个答案:

答案 0 :(得分:1)

你基本上做的是将字节复制到缓冲区中,然后再解析它们。你可以一气呵成,如下:

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

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

我从我的内存库中取了这个例子,我认为它会比你现在使用的代码快得多,假设你只是试图检索值类型。