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

Wil*_*ins 12 c# performance pinvoke managed-c++

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

如何在涉及指针时进行P/Invoke

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

Dro*_*per 13

C++包装器应该更快,看看这个MSDN页面:

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

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

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

  • @DrorHelper还有一篇关于代码项目的文章.[PInvoke Performance](http://www.codeproject.com/Articles/253444/PInvoke-Performance),作者声称C++/CLI更快,但读者看到他使用SuppressUnmanagedCodeSecurity时使用的相同样本的不同结果.您可以从评论区域阅读它们. (2认同)

pli*_*nth 6

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

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

int GetFooCount();
IntPtr GetFoo(int n);
void ReleaseFoo(IntPtr p);
Run Code Online (Sandbox Code Playgroud)

这一切都很好,直到你开始在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); }
Run Code Online (Sandbox Code Playgroud)

总计== 1000,将是4002个托管/非托管转换.如果你有这个:

int GetFooCount();
void GetFoos(IntPtr[] arr, int start, int count);
void ReleaseFoos(IntPtr arr, int start, int count);
Run Code Online (Sandbox Code Playgroud)

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

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

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

根据我们的经验,如果你能够做到这一点,那么去C# - >托管C++包装器 - >静态库要好得多(如果可能的话).