P / Invoke和C ++ Wrappers之间的性能差异

时间:2009-09-16 14:29:24

标签: c# performance pinvoke managed-c++

在学习P / Invoke的过程中,我问过上一个问题:

  

How to P/Invoke when pointers are involved

但是,我不太明白在C#中使用P / Invoke而不是在托管C ++中创建包装器的含义。在C#中使用P / Invoke创建相同的DLL肯定会产生更清晰的界面,因为我可以在嵌入式资源上使用DLLImport,但是我自己编组的本机DLL的托管C ++包装器会有更好的性能吗?

2 个答案:

答案 0 :(得分:12)

C ++包装器应该更快,看看这个MSDN page

  

C ++ Interop使用最快的数据封送方法,而P / Invoke使用最强大的方法。这意味着C ++ Interop(以典型的C ++方式)默认提供最佳性能,程序员负责解决此行为不安全或不合适的情况。

所以基本上主要的原因是P / Invoke确实存在固定,blitting,错误检查,而C ++ interop只是推送堆栈上的参数并调用函数。

要记住的另一点是,C ++可以在一次调用中调用多个API,而P / Invoke通过地址传递的每个参数都会在每次调用时固定并取消固定,复制 并复制回来等。

答案 1 :(得分:6)

你会获得更好的表现吗?取决于你正在做什么以及你是如何做的。一般来说,您的性能影响更可能来自管理/非托管转换,而且您可以更好地削减更多。理想情况下,您与非托管代码的接口应该是厚实的而不是繁琐的。

假设你有一个非托管代码,它包含几千个对象的集合。您可以将这样的API公开给托管代码:

int GetFooCount();
IntPtr GetFoo(int n);
void ReleaseFoo(IntPtr p);

这一切都很好,直到你开始在C#中使用它,就像这样:

int total = API.GetFooCount();
IntPtr[] objects = new IntPtr[total];
for (int i=0; i < total; i++) {
    objects[i] = GetFoo(i);
}
// and later:
foreach (IntPtr p in objects) { ReleaseFoo(p); }
总计== 1000的

将是4002个托管/非托管转换。如果你有这个:

int GetFooCount();
void GetFoos(IntPtr[] arr, int start, int count);
void ReleaseFoos(IntPtr arr, int start, int count);

然后你可以用6个过渡做同样的工作。您认为哪个会表现得更好?

当然,下一个要问的重要问题是“这种性能提升是否值得?”所以记得先测量一下。

您应该注意的一件事是,当您使用托管C ++时,STL会发生有趣的事情。我有一些非托管库代码恰好使用STL。我的经验是,如果我曾经触及过托管C ++中的任何STL类型,那么所有这些类型都成为托管实现。最终结果是低级代码在迭代列表时进行托管/非托管转换。让人惊讶。我通过永远不会将STL类型暴露给托管C ++来解决这个问题。

根据我们的经验,如果你有能力这样做,那么去C# - &gt;托管C ++包装器 - &gt;静态库会好得多(如果可能的话)。