gpt4 book ai didi

.net - 如何使 Activator.CreateInstance 在完全空类型的情况下运行速度慢 20 倍

转载 作者:行者123 更新时间:2023-12-04 16:10:12 26 4
gpt4 key购买 nike

鉴于:

  • 名为 expression_host 的 .NET 程序集
  • 名为 CreateInstanceTest 的 .NET 程序集
  • CreateInstanceTest 在其配置文件中启用 NetFx40_LegacySecurityPolicy
  • expression_host 归属于 SecurityPermission(SecurityAction.RequestOptional)
  • CreateInstanceTest 加载 expression_host 程序集 - 砰!!! - 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

    解释:
  • 程序执行 500,000 次 new TestClass()和 500,000 次 Activator.CreateInstance(typeof(TestClass))
  • 然后它加载 expression_host 程序集
  • 然后重复步骤1。
  • 数字是毫秒。

  • 两个组件都非常小。这是代码:

    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>

    程序.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 相同的行为)
  • 调用已编译的 lambda 表达式
  • 调用 new泛型参数类型上的运算符 - 因为 new T()编译为 Activator.CreateInstance<T>() - 无赖。
  • 使用 Reflection.Emit 发出的动态方法 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/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com