首页 技术 正文
技术 2022年11月6日
0 收藏 894 点赞 310 浏览 23943 个字

目录

前文回顾

Microsofthttps://www.shuzhiduo.com/A/kmzL3kGbdG/Extensionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjection 之一:解析实现 提到了 Microsofthttps://www.shuzhiduo.com/A/kmzL3kGbdG/Extensionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjection 包含以下核心组件。

IServiceCallSite

组件实例化上下文,包含许多实现,仅列举其中的ConstantCallSiteCreateInstanceCallSiteConstructorCallSite如下。

Microsoft.Extensions.DependencyInjection 之三:展开测试

ConstructorCallSite既是IServiceCallSite的实现类,又复合引用IServiceCallSite,以表达自身参数的构建形式。

组件生命周期也使用IServiceCallSite表达,它们既从IServiceCallSite继承,也引用IServiceCallSite

Microsoft.Extensions.DependencyInjection 之三:展开测试

CallSiteFactory

当组件需要被实例化时,CallSiteFactory从维护的ServiceDescriptor查找注入方式,对类型注入的组件使用反射解析其构造函数,并递归解析其参数,最后缓存得到的IServiceCallSite实例。

Microsoft.Extensions.DependencyInjection 之三:展开测试

ServiceProviderEngine

ServiceProviderEngine是抽象类,内部依赖CallSiteRuntimeResolver完成基于反射的组件实例化,并缓存了组件实例化的委托。

Microsoft.Extensions.DependencyInjection 之三:展开测试

CompiledServiceProviderEngine

CompiledServiceProviderEngineServiceProviderEngine继承,内部依赖ExpressionResolverBuilder完成基于表达式树的组件实例化的委托。

Microsoft.Extensions.DependencyInjection 之三:展开测试

DynamicServiceProviderEngine

DynamicServiceProviderEngineCompiledServiceProviderEngine继承,它创建的委托比较特殊:

  • 该委托第1次执行实际是 ServiceProviderEngine 内部的CallSiteRuntimeResolver调用
  • 该委托第2次执行时开启异步任务,调用CompiledServiceProviderEngine内部的ExpressionResolverBuilder编译出委托并覆盖ServiceProviderEngine内部缓存。

Microsoft.Extensions.DependencyInjection 之三:展开测试

为了印证该逻辑,这里使用 LINQPad 6 进行探索,该代码可以在控制台中运行,但部分语句仅在 LINQPad 中生效。

void Main() {    var services = new ServiceCollection()        https://www.shuzhiduo.com/A/kmzL3kGbdG/AddTransient<IFoo1, Foo1>()        https://www.shuzhiduo.com/A/kmzL3kGbdG/BuildServiceProvider();    var engine = ReflectionExtensionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/GetNonPublicField(services, "_engine");    var realizedServices = (Systemhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Collectionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/IDictionary)ReflectionExtensionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/GetNonPublicProperty(engine, "RealizedServices");    for (int i = 0; i < 3; i++) {        serviceshttps://www.shuzhiduo.com/A/kmzL3kGbdG/GetRequiredService<IFoo1>(); //组件实例化        foreach (DictionaryEntry item in realizedServices) {            var title = Stringhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Format("Loop {0}, type {1}, hash {2}", i, ((Type)itemhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Key)https://www.shuzhiduo.com/A/kmzL3kGbdG/FullName, itemhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Valuehttps://www.shuzhiduo.com/A/kmzL3kGbdG/GetHashCode());            itemhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Valuehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Dump(title, depth: 2); //仅被 LINQPad 支持        }        Threadhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Sleep(10); //确保异步任务完成    }}class ReflectionExtensions {    public static Object GetNonPublicField(Object instance, String name) {        var type = instancehttps://www.shuzhiduo.com/A/kmzL3kGbdG/GetType();        var field = typehttps://www.shuzhiduo.com/A/kmzL3kGbdG/GetField(name, BindingFlagshttps://www.shuzhiduo.com/A/kmzL3kGbdG/NonPublic | BindingFlagshttps://www.shuzhiduo.com/A/kmzL3kGbdG/Instance);        return fieldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/GetValue(instance);    }    public static Object GetNonPublicProperty(Object instance, String name) {        var type = instancehttps://www.shuzhiduo.com/A/kmzL3kGbdG/GetType();        var property = typehttps://www.shuzhiduo.com/A/kmzL3kGbdG/GetProperty(name, BindingFlagshttps://www.shuzhiduo.com/A/kmzL3kGbdG/NonPublic | BindingFlagshttps://www.shuzhiduo.com/A/kmzL3kGbdG/Instance);        return propertyhttps://www.shuzhiduo.com/A/kmzL3kGbdG/GetValue(instance);    }}interface IFoo1 {    void Hello();}class Foo1 : IFoo1 {    public void Hello() {        Consolehttps://www.shuzhiduo.com/A/kmzL3kGbdG/WriteLine("Foo1https://www.shuzhiduo.com/A/kmzL3kGbdG/Hello()");    }}

运行该脚本,可以看到

  • 第1次和第2次组件实例化,委托相同,hash 值都是 688136691,都是Microsofthttps://www.shuzhiduo.com/A/kmzL3kGbdG/Extensionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/ServiceLookuphttps://www.shuzhiduo.com/A/kmzL3kGbdG/DynamicServiceProviderEngine的内部委托;
  • 第1次和第2次组件实例化的 callSite计数从1谈到2;
  • 第3次组件实例例,委托变成了Systemhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Object lambda_method(https://www.shuzhiduo.com/A/kmzL3kGbdG/https://www.shuzhiduo.com/A/kmzL3kGbdG/https://www.shuzhiduo.com/A/kmzL3kGbdG/),hash 值变成了 1561307880;

LINQPad 5 运行该脚本未能看到 hash 值变化,猜测是优化相关所致,考虑到DEBUG、单元测试和 LINQPad 6 已经实证,不再研究。

Microsoft.Extensions.DependencyInjection 之三:展开测试

Microsofthttps://www.shuzhiduo.com/A/kmzL3kGbdG/Extensionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjection 之二:使用诊断工具观察内存占用 对比了组件实例化前后的内存变化如下图,从第3次开始组件实例化的性能大幅提升。

Microsoft.Extensions.DependencyInjection 之三:展开测试

在以上基础上得到作了小结:

Microsofthttps://www.shuzhiduo.com/A/kmzL3kGbdG/Extensionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjection 并非是银弹,它的便利性是一种空间换时间的典型,我们需要对以下情况有所了解:

  • 重度使用依赖注入的大型项目启动过程相当之慢;
  • 如果单次请求需要实例化的组件过多,前期请求的内存开销不可轻视;
  • 由于实例化伴随着递归调用,过深的依赖将不可避免地导致堆栈溢出;

测试参数

Microsofthttps://www.shuzhiduo.com/A/kmzL3kGbdG/Extensionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjection 中抽象类Microsofthttps://www.shuzhiduo.com/A/kmzL3kGbdG/Extensionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/ServiceLookuphttps://www.shuzhiduo.com/A/kmzL3kGbdG/ServiceProviderEngine有以下实现

  • Microsofthttps://www.shuzhiduo.com/A/kmzL3kGbdG/Extensionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/ServiceLookuphttps://www.shuzhiduo.com/A/kmzL3kGbdG/CompiledServiceProviderEngine
  • Microsofthttps://www.shuzhiduo.com/A/kmzL3kGbdG/Extensionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/ServiceLookuphttps://www.shuzhiduo.com/A/kmzL3kGbdG/DynamicServiceProviderEngine
  • Microsofthttps://www.shuzhiduo.com/A/kmzL3kGbdG/Extensionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/ServiceLookuphttps://www.shuzhiduo.com/A/kmzL3kGbdG/ExpressionsServiceProviderEngine
  • Microsofthttps://www.shuzhiduo.com/A/kmzL3kGbdG/Extensionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/ServiceLookuphttps://www.shuzhiduo.com/A/kmzL3kGbdG/RuntimeServiceProviderEngine
  • Microsofthttps://www.shuzhiduo.com/A/kmzL3kGbdG/Extensionshttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/ServiceLookuphttps://www.shuzhiduo.com/A/kmzL3kGbdG/ILEmitServiceProviderEngine

RuntimeServiceProviderEngine 是对 ServiceProviderEngine 的原样继承可以忽略,ExpressionsServiceProviderEngineCompiledServiceProviderEngine都是表达式树的使用也没有差异。ILEmitServiceProviderEngine是 emit 相关的实现。

aspnet/DependencyInjection 获取到的分支release/2https://www.shuzhiduo.com/A/kmzL3kGbdG/1 后,提取到ServiceProviderEngineCompiledServiceProviderEngineILEmitServiceProviderEngine等核心实现,再编写控制台程序,对依赖注入中反射、表达式树、emit 3种实现方式的开销和性能上进行探索。

程序使用启动参数控制组件实例化行为,并记录测试结果,以下是程序启动参数的解释。

Microsoft.Extensions.DependencyInjection 之三:展开测试

-m|method

实例化方式,使用反射、表达式树与 Emit 参与了测试,分别对应:

  • ref:使用反射实例化组件,实质是对 CallSiteRuntimeResolver 的调用;
  • exp:使用表达式树实例化组件,实质是对 ExpressionResolverBuilder 的调用;
  • emit:使用 emit 实例化组件,实质是对 ILEmitResolverBuilder 的调用;
Action<Type, Boolean> handle = default;if (method == "ref"){    handle = GetRefService;}else if (method == "exp"){    handle = GetExpService;}else if (method == "emit"){    handle = GetEmitService;}

-t|target

实例化目标,使用选取以下两种,配合参数 -n|number 使用

  • foo:使用 IFoo_{n} 作为实例化目标,已定义了 IFoo_0、IFoo_1、IFoo_2 至 IFoo_9999 共1万个接口与对应实现
  • bar:使用 IBar_{n} 作为实例化目标,只定义了 IBar_100、IBar_1000、IBar_5000、IBar_10000 共4个接口,每个实现均以 IFoo 作为构造函数的参数,
    • IBar_100:使用 IFoo_0、IFoo_1 至 IFoo_99 作为构造函数参数;
    • IBar_1000:使用 IFoo_0、IFoo_1 至 IFoo_999 作为构造函数参数;
    • IBar_5000:使用 IFoo_0、IFoo_1 至 IFoo_4999 作为构造函数参数;
    • IBar_10000:使用 IFoo_0、IFoo_1 至 IFoo_9999 作为构造函数参数;

该部分同 大量接口与实现类的生成 一样仍然使用脚本生成。

-n|number

帮助指示实例化的目标及数量

  • 100:target = foo 为从 IFoo_0、IFoo_1 至 IFoo_100 共100个接口,target =bar 则仅为 IBar_100;
  • 1000:target = foo 为从 IFoo_0、IFoo_1 至 IFoo_1000 共1000个接口,target = bar 则仅为 IBar_1000;
  • 5000:target = foo 为从 IFoo_0、IFoo_1 至 IFoo_5000 共5000个接口,target =bar 则仅为 IBar_5000;
  • 10000:target = foo 为从 IFoo_0、IFoo_1 至 IFoo_10000 共10000个接口,target =bar 则仅为 IBar_10000;

-c|cache

缓存行为,cache = false 时每次都构建委托,cache = true 则把构建委托缓存起来重复使用。GetRefService()实现如下,GetExpService()GetEmitService()相似。

static void GetRefService(Type type, Boolean cache){    var site = _expEnginehttps://www.shuzhiduo.com/A/kmzL3kGbdG/CallSiteFactoryhttps://www.shuzhiduo.com/A/kmzL3kGbdG/CreateCallSite(type, new CallSiteChain());    Func<ServiceProviderEngineScope, object> func;    if (cache)    {        func = _expEnginehttps://www.shuzhiduo.com/A/kmzL3kGbdG/RealizedServiceshttps://www.shuzhiduo.com/A/kmzL3kGbdG/GetOrAdd(type, scope => _expEnginehttps://www.shuzhiduo.com/A/kmzL3kGbdG/RuntimeResolverhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Resolve(site, scope));    }    else    {        func = scope => _expEnginehttps://www.shuzhiduo.com/A/kmzL3kGbdG/RuntimeResolverhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Resolve(site, scope);        _expEnginehttps://www.shuzhiduo.com/A/kmzL3kGbdG/RealizedServices[type] = func;    }    if (func == null)    {        _loggerhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Warn("Cache miss");        return;    }    var obj = func(_expEnginehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Root);    if (obj == null)    {        throw new NotImplementedException();    }}

-l|loop

重复执行若干次,每次均记录测试时长

static void TestBar(Action<Type, Boolean> handle, String method, Boolean cache, Type type){    _watchhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Restart();    handle(type, cache);    _watchhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Stop();    _loggerhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Info("method {0}, cache {1}, target {2}, cost {3}",        method, cache, typehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Name, _watchhttps://www.shuzhiduo.com/A/kmzL3kGbdG/ElapsedMilliseconds);}https://www.shuzhiduo.com/A/kmzL3kGbdG/https://www.shuzhiduo.com/A/kmzL3kGbdG/https://www.shuzhiduo.com/A/kmzL3kGbdG/TestBar(handle, method, false, number);for (int i = 1; i < loop; i++){    TestBar(handle, method, cache, number);}

由于本测试的重点是对比使用反射、表达式树与 emit 的性能与开销,故程序启动后首先遍历 ServiceCollection 对每个组件调用 CallSiteFactoryhttps://www.shuzhiduo.com/A/kmzL3kGbdG/CreateCallSite(Type serviceType),确保组件的上下文已经被创建和缓存。

启动测试

对以上参数进行组合,得到以下启动方式,测试结果异步写入日志文件供后续解析。

# 启用委托缓存行为,实例化以 IFoo_ 作为命名前缀注入的服务https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t foo -c true -n 100 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t foo -c true -n 1000 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t foo -c true -n 5000 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t foo -c true -n 10000 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t foo -c true -n 100 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t foo -c true -n 1000 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t foo -c true -n 5000 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t foo -c true -n 10000 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t foo -c true -n 100 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t foo -c true -n 1000 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t foo -c true -n 5000 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t foo -c true -n 10000 -l 100# 禁用委托缓存行为,实例化以 IFoo_ 作为命名前缀注入的服务https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t foo -c false -n 100 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t foo -c false -n 1000 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t foo -c false -n 5000 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t foo -c false -n 10000 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t foo -c false -n 100 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t foo -c false -n 1000 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t foo -c false -n 5000 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t foo -c false -n 10000 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t foo -c false -n 100 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t foo -c false -n 1000 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t foo -c false -n 5000 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t foo -c false -n 10000 -l 50# 启用委托缓存行为,实例化 IBar_100、IBar_1000、IBar_5000、IBar_10000https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t bar -c true -n 100 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t bar -c true -n 1000 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t bar -c true -n 5000 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t bar -c true -n 10000 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t bar -c true -n 100 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t bar -c true -n 1000 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t bar -c true -n 5000 -l 100# https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t bar -c true -n 10000 -l 100 # 请求无法完成,抛出 IL 相关异常https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t bar -c true -n 100 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t bar -c true -n 1000 -l 100https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t bar -c true -n 5000 -l 100# https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t bar -c true -n 10000 -l 100 # 请求无法完成,抛出 IL 相关异常# 禁用委托缓存行为,实例化 IBar_100、IBar_1000、IBar_5000、IBar_10000https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t bar -c false -n 100 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t bar -c false -n 1000 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t bar -c false -n 5000 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m ref -t bar -c false -n 10000 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t bar -c false -n 100 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t bar -c false -n 1000 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t bar -c false -n 5000 -l 50# https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m exp -t bar -c false -n 10000 -l 50 # 请求无法完成,抛出 IL 相关异常https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t bar -c false -n 100 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t bar -c false -n 1000 -l 50https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t bar -c false -n 5000 -l 50# https://www.shuzhiduo.com/A/kmzL3kGbdG//LeoninewAxehttps://www.shuzhiduo.com/A/kmzL3kGbdG/Scaffoldhttps://www.shuzhiduo.com/A/kmzL3kGbdG/DependencyInjectionhttps://www.shuzhiduo.com/A/kmzL3kGbdG/Apphttps://www.shuzhiduo.com/A/kmzL3kGbdG/exe -m emit -t bar -c false -n 10000 -l 50 # 请求无法完成,抛出 IL 相关异常

值得一提的是,表达式树和 emit 均无法完成 IBar_10000 的实例化,执行中抛出相同异常 "Systemhttps://www.shuzhiduo.com/A/kmzL3kGbdG/InvalidProgramException: The JIT compiler encountered invalid IL code or an internal limitationhttps://www.shuzhiduo.com/A/kmzL3kGbdG/"

Microsoft.Extensions.DependencyInjection 之三:展开测试

测试结果

使用 LINQPad 编写脚本解析日志,对解析结果使用 Excel 透视作表,得到耗时平均值与标准差。

Microsoft.Extensions.DependencyInjection 之三:展开测试

对于本测试使用到的以 IFoo_ 和 IBar_ 作为命名前缀的接口来说:

  • 1万余接口的注入时间为 10s 左右;
  • 1万余接口的组件的上下文创建时间在 0https://www.shuzhiduo.com/A/kmzL3kGbdG/6s 左右;
  • 开启委托缓存时,所有实例化方式都能获益;
  • 所有方式实例化 IBar_N 均比实例化 IFoo_0 至 IFoo_N 快非常多;

反射

  • 对缓存不敏感(控制台为 dotnet 3https://www.shuzhiduo.com/A/kmzL3kGbdG/0 版本);
  • 组件数量增长时,内存使用平稳,完成10000个 IFoo 实例化完成后进程内存增长 49https://www.shuzhiduo.com/A/kmzL3kGbdG/1MB-35https://www.shuzhiduo.com/A/kmzL3kGbdG/9MB=13https://www.shuzhiduo.com/A/kmzL3kGbdG/2MB;

表达式树

  • 随着组件数量增长,对缓存越发敏感;
  • 内存需求增长,完成10000个 IFoo 实例化后进程内存增长75https://www.shuzhiduo.com/A/kmzL3kGbdG/7MB-35https://www.shuzhiduo.com/A/kmzL3kGbdG/9MB=39https://www.shuzhiduo.com/A/kmzL3kGbdG/8MB;
  • 实例化依赖众多的组件时,在缓存下的耗时几乎忽略;

Emit 与表达式差异不大

  • 同表达式树对缓存敏感
  • 内存需求增长,完成10000个 IFoo 实例化后进程内存增长77https://www.shuzhiduo.com/A/kmzL3kGbdG/7MB-35https://www.shuzhiduo.com/A/kmzL3kGbdG/9MB=41https://www.shuzhiduo.com/A/kmzL3kGbdG/8MB;
  • 耗时更不稳定

开销对比

对比1:开启缓存,实例化 IFoo_ 相关组件

Microsoft.Extensions.DependencyInjection 之三:展开测试

对比2:开启缓存,实例化 IBar_ 相关组件

Microsoft.Extensions.DependencyInjection 之三:展开测试

表达树与 emit 方式均无法完成实例化 IBar_10000

对比3:关闭缓存,实例化 IFoo_ 相关组件

Microsoft.Extensions.DependencyInjection 之三:展开测试

对比4:关闭缓存,实例化 IBar_ 相关组件

Microsoft.Extensions.DependencyInjection 之三:展开测试

表达树与 emit 方式均无法完成实例化 IBar_10000

相对于使用反射来说,不开启缓存时表达式树和 emit 既慢内存消耗又高——无论是实例化 IFoo_ 相关组件还是 IBar_ 相关组件,它们均达到更高的内存占用,又频繁地触发 GC,最终 CPU 使用率居高不下。

测试中未使用 GChttps://www.shuzhiduo.com/A/kmzL3kGbdG/SuppressFinalize()处理实例化得到的组件,大量的 IFoo_ 实例回收影响判断,IBar_ 没有这个问题故放出截图。

Microsoft.Extensions.DependencyInjection 之三:展开测试

Microsoft.Extensions.DependencyInjection 之三:展开测试Microsoft.Extensions.DependencyInjection 之三:展开测试

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,085
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,560
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,409
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,182
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,819
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,902