鉴于:
expression_host
CreateInstanceTest
SecurityPermission(SecurityAction.RequestOptional)
Activator.CreateInstance
是 toast 请观察输出:
new() = 13, Activator.CreateInstance() = 111
Just loaded expression_host, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
new() = 6, Activator.CreateInstance() = 1944
解释:
new TestClass()
和500,000次Activator.CreateInstance(typeof(TestClass))
两个组件都非常小。这是代码:
CreateInstanceTest
CreateInstanceTest.csproj :
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{83690315-C8AC-4C52-9CDD-334115F521C0}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>CreateInstanceTest</RootNamespace>
<AssemblyName>CreateInstanceTest</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<OutputPath>bin\$(Configuration)\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<Optimize>false</Optimize>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Users\mkharitonov\Documents\Visual Studio 2012\Projects\CreateInstanceTest\expression_host\expression_host.csproj">
<Project>{01f4b604-d5a3-454f-aff7-e1f5c43d293e}</Project>
<Name>expression_host</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Program.cs :
using System;
using System.Diagnostics;
namespace CreateInstanceTest
{
internal class TestClass
{
}
internal class Program
{
public static void Main()
{
const int COUNT = 500000;
long newTime;
long createInstanceTime;
DoOneRound(COUNT, out newTime, out createInstanceTime);
Console.WriteLine("new() = {0}, Activator.CreateInstance() = {1}", newTime, createInstanceTime);
ScrewThingsUp();
DoOneRound(COUNT, out newTime, out createInstanceTime);
Console.WriteLine("new() = {0}, Activator.CreateInstance() = {1}", newTime, createInstanceTime);
Console.WriteLine("Press any key to terminate ...");
Console.ReadKey();
}
public static void DoOneRound(int count, out long newTime, out long createInstanceTime)
{
var sw = new Stopwatch();
sw.Start();
for (int index = 0; index < count; ++index)
{
// ReSharper disable ObjectCreationAsStatement
new TestClass();
// ReSharper restore ObjectCreationAsStatement
}
sw.Stop();
newTime = sw.ElapsedMilliseconds;
var type = typeof(TestClass);
sw.Restart();
for (int index = 0; index < count; ++index)
{
Activator.CreateInstance(type);
}
sw.Stop();
createInstanceTime = sw.ElapsedMilliseconds;
}
private static void ScrewThingsUp()
{
Console.WriteLine("Just loaded {0}", typeof(ReportExprHostImpl).Assembly.FullName);
}
}
}
app.config :
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<NetFx40_LegacySecurityPolicy enabled="true"/>
</runtime>
</configuration>
expression_host
expression_host.csproj :
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{01F4B604-D5A3-454F-AFF7-E1F5C43D293E}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<AssemblyName>expression_host</AssemblyName>
<OutputType>Library</OutputType>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\$(Configuration)\</OutputPath>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<Compile Include="ReportExprHostImpl.cs" />
</ItemGroup>
</Project>
ReportExprHostImpl.cs :
using System.Security.Permissions;
[assembly: SecurityPermission(SecurityAction.RequestOptional)]
public class ReportExprHostImpl
{
}
就是这样。
现在是什么问题?问题是如何处理它。这实际上是真实案例的最小复制,与A case of abysmal degradation of Activator.CreateInstance performance有关
在实际的应用程序中,我们必须运行报告,并且被
NetFx40_LegacySecurityPolicy
所困扰,这会使我们的应用程序的某些部分执行得很糟糕。最后,在实际应用程序中,我们无法更改表达式主机程序集的代码,因为它们是由Microsoft报告框架动态构建的。
所以,我们能做些什么?
编辑
将
[assembly: SecurityTransparent]
添加到CreateInstanceTest程序集似乎可以改善:new() = 6, Activator.CreateInstance() = 106
Just loaded expression_host, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
new() = 14, Activator.CreateInstance() = 904
现在
Activator.CreateInstance
仅慢9倍,而不是20倍。但仍然慢9倍!编辑2
这似乎是.NET内部的事情。托管探查器(ANTS)并不是很有用。
其他受影响的方法:
MethodInfo.Invoke
(与Activator.CreateInstance
相同的行为)new
运算符-前提是new T()
编译为Activator.CreateInstance<T>()
-bummer。 null
所有者一起发出的动态方法-请参阅DynamicMethod
重载接受owner
参数。 我们未能解决此问题,但是在我们的案例中,用动态发出的构造函数(具有所有者类型)替换
Activator.CreateInstance
解决了我们的问题。这是一种解决方法,因为其他方法仍然存在问题。编辑1
顺便说一句,我们就此问题与Microsoft支持部门联系,事实证明这完全是浪费时间。我们可以从他们那里得到的最好的是这就是事实。
最佳答案
也许这会有所帮助:http://ayende.com/blog/3167/creating-objects-perf-implications
我也将尝试单独使用ConstructorInfo
而不是在包装和发出构造代码之前调用Activator.CreateInstance
(我不记得Activator.CreateInstance
是否这样做,因为这是建议的解决方案的一部分,因此我在移动之前就已经尝试过了上)。
关于.net - 如何使用完全空的类型使Activator.CreateInstance的运行速度慢约20倍,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21191291/