我发现从C ++ / CX Windows运行时组件实例化WinRT对象会降低性能,并且我不知道问题是由于C ++ / CX项目中的配置错误还是因为编译器中的问题(我m使用Visual Studio 2017 v15.7.4)。
我已经创建了一个带有简单示例的存储库来测试性能损失:https://github.com/joseangelmt/UWP-CPP_CX-PERFORMANCE-ISSUES,但我将在此处进行解释:
该存储库包含一个应用程序,该应用程序用于测量从C#和C ++ / CX Windows运行时组件实例化WinRT对象的性能。
解决方案中包含三个项目:
WindowsRuntimeComponent1中的Class1实现很简单:
namespace WindowsRuntimeComponent1
{
public ref class Class1 sealed
{
public:
Class1() {}
};
}
,WindowsRuntimeComponent2中的工厂也很简单:
namespace WindowsRuntimeComponent2
{
public ref class Factory sealed
{
public:
static WindowsRuntimeComponent1::Class1^ CreateObject()
{
return ref new WindowsRuntimeComponent1::Class1();
}
static WindowsRuntimeComponent1::Class1^ CreateNullObject()
{
return nullptr;
}
};
}
运行应用程序时,您有一个按钮来开始测试。当您按下按钮时,将开始三个测试:
直接从C#创建10000个WindowsRuntimeComponent1.Class1对象。由于WindowsRuntimeComponent1是C ++ / CX项目,因此存在跨边界操作。
var list = new List<Class1>();
for (int i = 0; i < 100000; i++)
list.Add(new Class1());
使用工厂WindowsRuntimeComponent2.Factory间接创建10000个WindowsRuntimeComponent1.Class1对象,因此也存在从应用程序到WindowsRuntimeComponent2的跨边界操作,因此由于跨边界操作而导致的性能降低应该相同。 / p>
var list = new List<Class1>();
for (int i = 0; i < 100000; i++)
list.Add(Factory.CreateObject());
从WindowsRuntimeComponent2.Factory创建10000个“空”对象,因此也存在从应用程序到WindowsRuntimeComponent2的跨边界操作,但是没有任何实例化。
var list = new List<Class1>();
for (int i = 0; i < 100000; i++)
list.Add(Factory.CreateNullObject());
结果是,在我的计算机上,第一次测试大约需要 0.39秒完成,而第二次测试大约需要 25秒。第三次测试大约是 0.06秒,因此在跨边界时不会造成性能损失,而在使用ref new
从C ++ / CX组件实例化对象时,性能不会受到影响。
我知道ref new
为您隐藏了很多工作,但是从C#角度来看应该是相同的(实例化工厂对象,创建对象,QueryInterface等),所以我不敢相信这种性能损失从C ++ / CX实例化对象是正常的。