当我将 c++ DLL(我从 c# 调用)重新生成为 /CLR(最初是本机)时,性能下降了一半



当我将 DLL 生成选项从本机更改为/CLR 以便可以跨 c#/c++ 边界进行调试时,性能降低了一半。

我开发了一个具有特定高性能算法的本机C++ DLL,以解决我的计算问题。 我需要将此 DLL 插入到由业务合作伙伴开发的 C# 应用程序中,它用于替换其性能较低的算法。 一切都很顺利,我使用静态包装器调用插入我的 DLL,DLL 算法运行良好,性能比原始算法提高了 2 倍,但无法跨边界调试。 然后,我将 c++ DLL 生成设置从本机切换到/CLR,以便能够跨 c#/c++ DLL 边界进行调试,并且性能下降了一半。

不知道为什么会这样。

C++ DLL 端:

extern "C"
{
__declspec(dllexport) void* NewCalc()
{
return (void*)new CalcCL;
}
__declspec(dllexport) double Calc(void* sCalc, int *Buf, int Cnt)
{
return ((CalcCl*)sCalc)->Calc(Buf, Cnt);
}
}

C# 端:

[DllImport("CalcDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int NewCalc();
[DllImport("CalcDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern double Calc(int sCalc, int[] Buf, int Cnt);
...
int sCalc = NewCalc();
...
double res;
int[] MyBuf = new int[1000];
// <Code that fills MyBuf with target data for algorithm>
res = Calc(sCalc, MyBuf, 1000);

使用给定的接口,使用/clr 进行编译根本没有任何好处。 通过右键单击主 C# 项目>"属性">"调试"选项卡>勾选"启用本机代码调试"复选框,使本机C++代码可调试。 这将启用托管和非托管调试引擎。 不能单步执行本机代码,需要 Calc() 函数上的断点才能实现调试引擎更改。 如果设置断点很尴尬,您可能仍然倾向于用本机C++编写的单元测试。

您需要注意的另一件事是,您正在构建启用了调试设置的C++代码。 你现在明白了,这就是为什么代码似乎慢了一半。 仅使用发布生成设置执行性能测试,以确保已启用优化器。 最好的办法是在 C# 解决方案中包含本机C++项目,以便始终生成正确的风格。 并且必须确保将正确的 DLL 复制到 C# 主项目的生成目录中,通常使用生成后事件完成。 对于调试和发布配置,该复制步骤必须不同。

请注意,[DllImport] 声明不正确。 NewCalc() 的返回类型必须是 IntPtr,因此它也可以在 64 位代码中使用。 对 C++ 代码的 64 位构建进行性能测试是您想要尝试的其他方法,如果 Calc() 函数使用浮点数学,它可以提高性能。 实际上,使用/clr 对于使界面更好很有用,但是您必须学习如何编写 C++/CLI 代码并避免使用/clr 构建本机C++代码。

最新更新