我正在考虑将我的 C# 项目中的一小部分代码移植到 C/ASM 以获得性能优势。(这部分代码使用了许多按位运算,并且是少数几个使用本机代码可能会真正提高性能的地方之一。)然后我计划通过 P/Invoke 在单独的 DLL 中简单地调用本机函数。现在,将在托管代码和本机代码之间传递的唯一数据将是纯原始类型(bool、int、long、一维数组等)。所以我的问题是:仅使用原始类型的 P/invoke 会有任何重大开销吗?我知道在使用更复杂的类型时会产生大量开销,因为它们需要编组(固定/复制),但也许在我的情况下它会相对有效(甚至与从本机 DLL 本身调用代码相比)?如果有人能为我澄清这个问题,解释性能优势/命中的程度及其背后的原因,将不胜感激。完成整个任务的另一种方法也将受到欢迎,但由于 C# 缺乏对内联汇编/CIL 的支持,我不相信有一个。
5 回答
从 MSDN(http://msdn.microsoft.com/en-us/library/aa712982.aspx):
“PInvoke 每次调用的开销在 10 到 30 个 x86 指令之间。除了这个固定成本之外,封送处理会产生额外的开销。在托管和非托管代码中具有相同表示的 blittable 类型之间没有封送处理成本。例如,有在 int 和 Int32 之间进行转换是免费的。”
因此,它相当便宜,但您应该像往常一样仔细测量以确保您从中受益,并记住任何维护开销。顺便说一句,对于任何复杂的互操作,我会推荐 C++/CLI(“托管”C++)而不是 P/Invoke,尤其是在您熟悉 C++ 的情况下。
我似乎记得听说每个 P/Invoke 调用至少有 30 个机器操作开销。但是忽略理论,分析您的选择并选择最快的。
我会亲自设置一个使用 C# 和非托管 C++ 编写的简单表达式的测试工具,然后分析应用程序以查看您正在使用哪种性能增量。
其他需要考虑的事情是,您将在应用程序中引入维护问题,特别是如果您有初级开发人员希望维护代码。确保您知道在性能以及代码清晰度和可维护性方面您正在获得什么以及您正在失去什么。
顺便说一句,JIT 处理的 C# 代码在算术运算方面的性能应该与 C++ 相当。
ngen
通过在最终用户的计算机上使用(作为安装过程的一部分),您可以生成 .NET 程序集的已编译、优化版本。
根据我的经验,正确格式化的 C#(例如,将分配保持在循环之外)会表现得非常好。
此链接提供了一些见解: http: //www.codeproject.com/Articles/253444/PInvoke-Performance
还要注意应用 [SuppressUnmanagedCodeSecurity] 属性时的性能差异。