网站开发如何下载服务器文档/北京做网站的公司排行
依赖注入(Dependency Injection,简称DI)是一种设计模式,用于解耦组件(服务)之间的依赖关系。它通过将依赖关系的创建和管理交给外部容器来实现,而不是在组件(服务)内部直接创建依赖对象。
咱就是通过 IServiceCollection
和 IServiceProvider
来实现的,他们直接被收入到了runtime libraries,在整个.NET平台下通用!
3.1 ServiceCollection
IServiceCollection
本质是一个 ServiceDescriptor
而 ServiceDescriptor
则是用于描述服务类型,实现和生命周期
public interface IServiceCollection : IList<ServiceDescriptor>,ICollection<ServiceDescriptor>,IEnumerable<ServiceDescriptor>,IEnumerable;
官方提供一些列拓展帮助我们向服务容器中添加服务描述,具体在 ServiceCollectionServiceExtensions
builder.Services.AddTransient<StudentService>();
builder.Services.AddKeyedTransient<IStudentRepository, StudentRepository>("a");
builder.Services.AddKeyedTransient<IStudentRepository, StudentRepository2>("b");
builder.Services.AddTransient<TransientService>();
builder.Services.AddScoped<ScopeService>();
builder.Services.AddSingleton<SingletonService>();
3.2 ServiceProvider
IServiceProvider
定义了一个方法 GetService
,帮助我们通过给定的服务类型,获取其服务实例
public interface IServiceProvider
{object? GetService(Type serviceType);
}
下面是 GetService
的默认实现(如果不给定engine scope,则默认是root)
public object? GetService(Type serviceType) => GetService(ServiceIdentifier.FromServiceType(serviceType), Root);
也就是
internal object? GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope)
{if (_disposed){ThrowHelper.ThrowObjectDisposedException();}// 获取服务标识符对应的服务访问器ServiceAccessor serviceAccessor = _serviceAccessors.GetOrAdd(serviceIdentifier, _createServiceAccessor);// 执行解析时的hockOnResolve(serviceAccessor.CallSite, serviceProviderEngineScope);DependencyInjectionEventSource.Log.ServiceResolved(this, serviceIdentifier.ServiceType);// 通过服务访问器提供的解析服务,得到服务实例object? result = serviceAccessor.RealizedService?.Invoke(serviceProviderEngineScope);System.Diagnostics.Debug.Assert(result is null || CallSiteFactory.IsService(serviceIdentifier));return result;
}
其中,服务标识符 ServiceIdentifier
其实就是包了一下服务类型,和服务Key(为了.NET8的键化服务)
internal readonly struct ServiceIdentifier : IEquatable<ServiceIdentifier>
{public object? ServiceKey { get; }public Type ServiceType { get; }
}
显而易见的,我们的服务解析是由 serviceAccessor.RealizedService
提供,而创建服务访问器 serviceAccessor
只有一个实现 CreateServiceAccessor
private ServiceAccessor CreateServiceAccessor(ServiceIdentifier serviceIdentifier)
{// 通过 CallSiteFactory 获取服务的调用点(CallSite),这是服务解析的一个表示形式。ServiceCallSite? callSite = CallSiteFactory.GetCallSite(serviceIdentifier, new CallSiteChain());// 如果调用站点不为空,则继续构建服务访问器。if (callSite != null){DependencyInjectionEventSource.Log.CallSiteBuilt(this, serviceIdentifier.ServiceType, callSite);// 触发创建调用站点的相关事件。OnCreate(callSite);// 如果调用站点的缓存位置是根(Root),即表示这是一个单例服务。if (callSite.Cache.Location == CallSiteResultCacheLocation.Root){// 直接拿缓存内容object? value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root);return new ServiceAccessor { CallSite = callSite, RealizedService = scope => value };}// 通过引擎解析Func<ServiceProviderEngineScope, object?> realizedService = _engine.RealizeService(callSite);return new ServiceAccessor { CallSite = callSite, RealizedService = realizedService };}// 如果调用点为空,则它的实现服务函数总是返回 null。return new ServiceAccessor { CallSite = callSite, RealizedService = _ => null };
}
3.2.1 ServiceProviderEngine
ServiceProviderEngine
是服务商解析服务的执行引擎,它在服务商被初始化时建立。有两种引擎,分别是动态引擎和运行时引擎,在 NETFRAMEWORK || NETSTANDARD2_0 默认使用动态引擎。
private ServiceProviderEngine GetEngine(){ServiceProviderEngine engine;#if NETFRAMEWORK || NETSTANDARD2_0engine = CreateDynamicEngine();
#elseif (RuntimeFeature.IsDynamicCodeCompiled && !DisableDynamicEngine){engine = CreateDynamicEngine();}else{// Don't try to compile Expressions/IL if they are going to get interpretedengine = RuntimeServiceProviderEngine.Instance;}
#endifreturn engine;[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",Justification = "CreateDynamicEngine won't be called when using NativeAOT.")] // see also https://github.com/dotnet/linker/issues/2715ServiceProviderEngine CreateDynamicEngine() => new DynamicServiceProviderEngine(this);}
由于.NET Aot技术与dynamic技术冲突,因此Aot下只能使用运行时引擎,但动态引擎在大多情况下仍然是默认的。
动态引擎使用了emit技术,这是一个动态编译技术,而aot的所有代码都需要在部署前编译好,因此运行时无法生成新的代码。那运行时引擎主要使用反射,目标是在不牺牲太多性能的情况下,提供一个在aot环境中可行的解决方案。
我们展开动态引擎来看看它是如何解析服务的。
public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
{// 定义一个局部变量来跟踪委托被调用的次数int callCount = 0;return scope =>{// 当委托被调用时,先使用CallSiteRuntimeResolver.Instance.Resolve方法来解析服务。这是一个同步操作,确保在编译优化之前,服务可以被正常解析。var result = CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);// 委托第二次被调用,通过UnsafeQueueUserWorkItem在后台线程上启动编译优化if (Interlocked.Increment(ref callCount) == 2){// 将一个工作项排队到线程池,但不捕获当前的执行上下文。_ = ThreadPool.UnsafeQueueUserWorkItem(_ =>{try{// 用编译优化后的委托替换当前的服务访问器,主要用到emit/expression技术_serviceProvider.ReplaceServiceAccessor(callSite, base.RealizeService(callSite));}catch (Exception ex){DependencyInjectionEventSource.Log.ServiceRealizationFailed(ex, _serviceProvider.GetHashCode());Debug.Fail($"We should never get exceptions from the background compilation.{Environment.NewLine}{ex}");}},null);}return result;};
}
这个实现的关键思想是,第一次解析服务时使用一个简单的运行时解析器,这样可以快速返回服务实例。然后,当服务再被解析,它会在后台线程上启动一个编译过程,生成一个更高效的服务解析委托。一旦编译完成,新的委托会替换掉原来的委托,以后的服务解析将使用这个新的、更高效的委托。这种方法可以在不影响应用程序启动时间的情况下,逐渐优化服务解析的性能。
3.2.2 ServiceProviderEngineScope
ServiceProviderEngineScope
闪亮登场,他是我们服务商的代言人,从定义不难看出他对外提供了服务商所具备的一切能力
internal sealed class ServiceProviderEngineScope : IServiceScope, IServiceProvider, IKeyedServiceProvider, IAsyncDisposable, IServiceScopeFactory
{// this scope中所有实现IDisposable or IAsyncDisposable的服务private List<object>? _disposables;// 解析过的服务缓存(其实就是scope生命周期的服务缓存,singleton生命周期的服务缓存都直接挂在调用点上了)internal Dictionary<ServiceCacheKey, object?> ResolvedServices { get; }// 实锤服务商代言人public IServiceProvider ServiceProvider => this;// 没错啦,通过root scope我们又能继续创建无数个scope,他们彼此独立public IServiceScope CreateScope() => RootProvider.CreateScope();
}
我们来观察他获取服务的逻辑,可以发现他就是很朴实无华的用着我们根服务商 ServiceProvider
,去解析服务,那 engine scope 呢,就是 this。现在我们已经隐约可以知道engine scope,就是为了满足scope生命周期而生。而 ResolvedServices
中存的呢,就是该scope中的所有scope生命周期服务实例啦,在这个scope中他们是唯一的。
public object? GetService(Type serviceType)
{if (_disposed){ThrowHelper.ThrowObjectDisposedException();}return RootProvider.GetService(ServiceIdentifier.FromServiceType(serviceType), this);
}
再来看另一个核心的方法:CaptureDisposable
,实现disposable的服务会被添加到 _disposables。
internal object? CaptureDisposable(object? service)
{// 如果服务没有实现 IDisposable or IAsyncDisposable,那么不需要捕获,直接原路返回if (ReferenceEquals(this, service) || !(service is IDisposable || service is IAsyncDisposable)){return service;}bool disposed = false;lock (Sync){if (_disposed) // 如果scope已经销毁则进入销毁流程{disposed = true;}else{_disposables ??= new List<object>();_disposables.Add(service);}}// Don't run customer code under the lockif (disposed) // 这表示我们在试图捕获可销毁服务时,scope就已经被销毁{if (service is IDisposable disposable){disposable.Dispose();}else{// sync over async, for the rare case that an object only implements IAsyncDisposable and may end up starving the thread pool.object? localService = service; // copy to avoid closure on other pathsTask.Run(() => ((IAsyncDisposable)localService).DisposeAsync().AsTask()).GetAwaiter().GetResult();}// 这种case会抛出一个ObjectDisposedExceptionThrowHelper.ThrowObjectDisposedException();}return service;
}
在engine scope销毁时,其作用域中所有scope生命周期且实现了disposable的服务(其实就是_disposable)呢,也会被一同的销毁。
public ValueTask DisposeAsync()
{List<object>? toDispose = BeginDispose(); // 获取_disposableif (toDispose != null){// 从后往前,依次销毁服务}
}
那么有同学可能就要问了:单例实例既然不存在root scope中,而是单独丢到了调用点上,那他是咋销毁的?压根没看到啊,那不得泄露了?
其实呀,同学们并不用担心这个问题。首先,单例服务的实例确实是缓存在调用点上,但 disable 服务仍然会被 scope 捕获呀(在下文会详细介绍)。在 BeginDispose 中的,我们会去判断,如果是 singleton case,且root scope 没有被销毁过,我们会主动去销毁喔~
if (IsRootScope && !RootProvider.IsDisposed()) RootProvider.Dispose();
3.3 ServiceCallSite
ServiceCallSite
的主要职责是封装服务解析的逻辑,它可以代表一个构造函数调用、属性注入、工厂方法调用等。DI系统使用这个抽象来表示服务的各种解析策略,并且可以通过它来生成服务实例。
internal abstract class ServiceCallSite
{protected ServiceCallSite(ResultCache cache){Cache = cache;}public abstract Type ServiceType { get; }public abstract Type? ImplementationType { get; }public abstract CallSiteKind Kind { get; }public ResultCache Cache { get; }public object? Value { get; set; }public object? Key { get; set; }public bool CaptureDisposable => ImplementationType == null ||typeof(IDisposable).IsAssignableFrom(ImplementationType) ||typeof(IAsyncDisposable).IsAssignableFrom(ImplementationType);
}
3.3.1 ResultCache
其中 ResultCache
定义了我们如何缓存解析后的结果
public CallSiteResultCacheLocation Location { get; set; } // 缓存位置
public ServiceCacheKey Key { get; set; } // 服务key(键化服务用的)
CallSiteResultCacheLocation
是一个枚举,定义了几个值
-
Root
:表示服务实例应该在根级别的IServiceProvider
中缓存。这通常意味着服务实例是单例的(Singleton),在整个应用程序的生命周期内只会创建一次,并且在所有请求中共享。
-
Scope
:表示服务实例应该在当前作用域(Scope)中缓存。对于作用域服务(Scoped),实例会在每个作用域中创建一次,并在该作用域内的所有请求中共享。
-
Dispose
:尽管这个名称可能会让人误解,但在ResultCache
的上下文中,Dispose
表示着服务是瞬态的(每次请求都创建新实例)。
-
None
:表示没有缓存服务实例。
ServiceCacheKey
结构体就是包了一下服务标识符和一个slot,用于适配多实现的
internal readonly struct ServiceCacheKey : IEquatable<ServiceCacheKey>
{public ServiceIdentifier ServiceIdentifier { get; }public int Slot { get; } // 那最后一个实现的slot是0
}
3.3.2 CallSiteFactory.GetCallSite
那我们来看看调用点是怎么创建的吧,其实上面已经出现过一次了:
private ServiceCallSite? CreateCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain)
{if (!_stackGuard.TryEnterOnCurrentStack()) // 防止栈溢出{return _stackGuard.RunOnEmptyStack(CreateCallSite, serviceIdentifier, callSiteChain);}// 获取服务标识符对应的锁,以确保在创建调用点时的线程安全。// 是为了保证并行解析下的调用点也只会被创建一次,例如:// C -> D -> A// E -> D -> Avar callsiteLock = _callSiteLocks.GetOrAdd(serviceIdentifier, static _ => new object());lock (callsiteLock){// 检查当前服务标识符是否会导致循环依赖callSiteChain.CheckCircularDependency(serviceIdentifier);// 首先尝试创建精确匹配的服务调用站点,如果失败,则尝试创建开放泛型服务调用站点,如果还是失败,则尝试创建枚举服务调用站点。如果所有尝试都失败了,callSite将为null。ServiceCallSite? callSite = TryCreateExact(serviceIdentifier, callSiteChain) ??TryCreateOpenGeneric(serviceIdentifier, callSiteChain) ??TryCreateEnumerable(serviceIdentifier, callSiteChain);return callSite;}
}
那服务点的创建过程我就简单概述一下啦
-
查找调用点缓存,存在就直接返回啦
-
服务标识符会被转成服务描述符
ServiceDescriptor
(key化服务不指定key默认取last)
-
计算
ServiceCallSite
,依次是:
-
TryCreateExact
计算 ResultCache
如果已经有实现实例了,则返回 ConstantCallSite
:表示直接返回已经创建的实例的调用点。
如果有实现工厂,则返回 FactoryCallSite
:表示通过工厂方法创建服务实例的调用点。
如果有实现类型,则返回 ConstructorCallSite
:表示通过构造函数创建服务实例的调用点。
-
TryCreateOpenGeneric
根据泛型定义获取服务描述符 ServiceDescriptor
计算 ResultCache
使用服务标识符中的具体泛型参数来构造实现的闭合类型
AOT兼容性测试(因为不能保证值类型泛型的代码已经生成)
如果成功闭合,则返回 ConstructorCallSite
:表示通过构造函数创建服务实例的调用点。
-
TryCreateEnumerable
确定类型是 IEnumerable<T>
AOT兼容性测试(因为不能保证值类型数组的代码已经生成)
如果 T
不是泛型类型,并且可以找到对应的服务描述符集合,则循环 TryCreateExact
否则,方向循环 TryCreateExact,然后方向循环 TryCreateOpenGeneric
3.4 CallSiteVisitor
好了,有了上面的了解我们可以开始探索服务解析的内幕了。服务解析说白了就是引擎围着 CallSiteVisitor
转圈圈,所谓的解析服务,其实就是访问调用点了。
protected virtual TResult VisitCallSite(ServiceCallSite callSite, TArgument argument)
{if (!_stackGuard.TryEnterOnCurrentStack()) // 一些校验,分栈啥的{return _stackGuard.RunOnEmptyStack(VisitCallSite, callSite, argument);}switch (callSite.Cache.Location){case CallSiteResultCacheLocation.Root: // 单例return VisitRootCache(callSite, argument);case CallSiteResultCacheLocation.Scope: // 作用域return VisitScopeCache(callSite, argument);case CallSiteResultCacheLocation.Dispose: // 瞬态return VisitDisposeCache(callSite, argument);case CallSiteResultCacheLocation.None: // 不缓存(ConstantCallSite)return VisitNoCache(callSite, argument);default:throw new ArgumentOutOfRangeException();}
}
为了方便展示,我们这里的解析器都拿运行时来说,因为内部是反射,而emit、expression实在是难以观看。
3.4.1 VisitRootCache
那我们来看看单例的情况下,是如何访问的:
protected override object? VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
{if (callSite.Value is object value){// Value already calculated, return it directlyreturn value;}var lockType = RuntimeResolverLock.Root;// 单例都是直接放根作用域的ServiceProviderEngineScope serviceProviderEngine = context.Scope.RootProvider.Root;lock (callSite){// 这里搞了个双检锁来确保在多线程环境中,同一时间只有一个线程可以执行接下来的代码块。// Lock the callsite and check if another thread already cached the valueif (callSite.Value is object callSiteValue){return callSiteValue;}object? resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext{Scope = serviceProviderEngine,AcquiredLocks = context.AcquiredLocks | lockType});// 捕获可销毁的服务serviceProviderEngine.CaptureDisposable(resolved);// 缓存解析结果到调用点上callSite.Value = resolved;return resolved;}
}
好,可以看到真正解析调用点的主角出来了 VisitCallSiteMain
,那这里的 CallSiteKind
上面计算 ServiceCallSite
时呢已经讲的很清楚啦,咱对号入座就行了
protected virtual TResult VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
{switch (callSite.Kind){case CallSiteKind.Factory:return VisitFactory((FactoryCallSite)callSite, argument);case CallSiteKind.IEnumerable:return VisitIEnumerable((IEnumerableCallSite)callSite, argument);case CallSiteKind.Constructor:return VisitConstructor((ConstructorCallSite)callSite, argument);case CallSiteKind.Constant:return VisitConstant((ConstantCallSite)callSite, argument);case CallSiteKind.ServiceProvider:return VisitServiceProvider((ServiceProviderCallSite)callSite, argument);default:throw new NotSupportedException(SR.Format(SR.CallSiteTypeNotSupported, callSite.GetType()));}
}
我们就看看最经典的通过构造函数创建服务实例的调用点 ConstructorCallSite
,很显然就是new嘛,只不过可能构造中依赖其它服务,那就递归创建呗。easy,其它几种太简单了大家自己去看看吧。
protected override object VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
{object?[] parameterValues;if (constructorCallSite.ParameterCallSites.Length == 0){parameterValues = Array.Empty<object>();}else{parameterValues = new object?[constructorCallSite.ParameterCallSites.Length];for (int index = 0; index < parameterValues.Length; index++){// 递归构建依赖的服务parameterValues[index] = VisitCallSite(constructorCallSite.ParameterCallSites[index], context);}}// new (xxx)return constructorCallSite.ConstructorInfo.Invoke(BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameterValues, culture: null);
}
3.4.2 VisitScopeCache
在访问单例缓存的时候呢,仅仅通过了一个double check lock就搞定了,因为人家全局的嘛,咱再来看看访问作用域缓存,会不会有什么不一样
protected override object? VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
{// Check if we are in the situation where scoped service was promoted to singleton// and we need to lock the rootreturn context.Scope.IsRootScope ?VisitRootCache(callSite, context) :VisitCache(callSite, context, context.Scope, RuntimeResolverLock.Scope);
}
哈哈,它果然很不一般啊,上来就来检查我们是否是 root scope。如果是这种case呢,则走 VisitRootCache
。但是奇怪啊,为什么访问 scope cache,所在 engine scope 能是 root scope?
还记得 ServiceProvider
获取的服务实例的核心方法吗?engine scope 他是传进来的,如果我们给一个 root scope,自然就出现的这种case,只是这种 case 特别罕见。
internal object? GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope)
VisitCache
的同步模型写的实在是酷,我们看 RuntimeResolverLock
的枚举就两个:Scope = 1
和 Root = 2
-
AcquiredLocks=Scope时
-
那 AcquiredLocks&false==0 显然成立,申请锁,也就是尝试独占改作用域的ResolvedServices
-
申请成功进入同步块,重新计算AcquiredLocks|true=1
-
如此,在该engine scope 中这条链路上的调用点都被占有,直到结束
-
AcquiredLocks=Root 时
-
那显然 engine scope 也应该是 root scope,那么走
VisitRootCache
case
-
在
VisitRootCache
通过DCL锁住 root scope 上链路涉及的服务点,直至结束
至此我们应该不难看出这个设计的精妙之处,即在非 root scope(scope生命周期)中,scope之间是互相隔离的,没有必要像 root scope(singleton生命周期)那样,在所有scope中独占服务点。
private object? VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine
{bool lockTaken = false;object sync = serviceProviderEngine.Sync;Dictionary<ServiceCacheKey, object?> resolvedServices = serviceProviderEngine.ResolvedServices;if ((context.AcquiredLocks & lockType) == 0){Monitor.Enter(sync, ref lockTaken);}try{// Note: This method has already taken lock by the caller for resolution and access synchronization.// For scoped: takes a dictionary as both a resolution lock and a dictionary access lock.if (resolvedServices.TryGetValue(callSite.Cache.Key, out object? resolved)){return resolved;}// scope服务的解析结果是放在engine scope的ResolvedServices上的,而非调用点resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext{Scope = serviceProviderEngine,AcquiredLocks = context.AcquiredLocks | lockType});serviceProviderEngine.CaptureDisposable(resolved);resolvedServices.Add(callSite.Cache.Key, resolved);return resolved;}finally{if (lockTaken){Monitor.Exit(sync);}}
}
3.4.3 VisitDisposeCache
我们看最后一个,也就是 Transient
case
protected override object? VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
{return context.Scope.CaptureDisposable(VisitCallSiteMain(transientCallSite, context));
}
异常的简单,我们沿用了scope的设计,但是我们没有进行任何缓存行为。即,每次都去访问调用点。
文章转载自:xiaolipro
原文链接:https://www.cnblogs.com/xiaolipro/p/17873575.html
相关文章:

.NET8 依赖注入
依赖注入(Dependency Injection,简称DI)是一种设计模式,用于解耦组件(服务)之间的依赖关系。它通过将依赖关系的创建和管理交给外部容器来实现,而不是在组件(服务)内部直…...

Ubuntu18安装(重启黑屏问题)
1. F10 进入bios,选择u盘里的ubuntu镜像 2.进入使用ubuntu,下载 3.重启,esc 4.ubuntu 安e进入 5. nomodeset() F10 保存启动 6. 7.没有网 手机usb提供网络 下载有限网卡驱动...

[PyTorch][chapter 4][李宏毅深度学习][Gradient Descent]
前言: 目录: 1: 梯度下降原理 2: 常见问题 3: 梯度更新方案 4: 梯度下降限制 一 梯度下降原理 机器学习的目标找到最优的参数,使得Loss 最小 为什么顺着梯度方向loss 就能下降了。主要原理是泰勒公式。 假设损失函数为 忽略二阶导数, 当 …...

利用proteus实现串口助手和arduino Mega 2560的串口通信
本例用到的proteus版本为8.13,ardunio IDE版本为2.2.1,虚拟串口vspd版本为7.2,串口助手SSCOM V5.13.1。软件的下载安装有很多教程,大家可以自行搜索,本文只介绍如何利用这4种软件在proteus中实现arduino Mega 2560的串…...

Web APIs—介绍、获取DOM对象、操作元素内容、综合案例—年会抽奖案例、操作元素属性、间歇函数、综合案例—轮播图定时器版
版本说明 当前版本号[20231204]。 版本修改说明20231204初版 目录 文章目录 版本说明目录复习变量声明 Web APIs - 第1天笔记介绍概念DOM 树DOM 节点document 获取DOM对象案例— 控制台依次输出3个li的DOM对象 操作元素内容综合案例——年会抽奖案例操作元素属性常用属性修改…...

题目:分糖果(蓝桥OJ 2928)
题目描述: 解题思路: 本题采用贪心思想 图解 题解: #include<bits/stdc.h> using namespace std;const int N 1e6 9; char s[N];//写字符串数组的一种方法,像数组一样***int main() {int n, x;cin >> n >> x;for(int …...

Leetcode刷题笔记——摩尔投票法
摩尔投票法的核心思想为对拼消耗。 摩你妈,学不会!!!! 229. 多数元素 II - 力扣(LeetCode)...

RabbitMq整合Springboot超全实战案例+图文演示+源码自取
目录 介绍 简单整合 简单模式 定义 代码示例 work模式 定义 代码示例 pubsub模式 定义 代码示例 routing模式 定义 代码示例 top模式 定义 代码 下单付款加积分示例 介绍 代码 可靠性投递示例 介绍 代码 交换机投递确认回调 队列投递确认回调 延迟消…...

10-Hadoop组件开发技术
单选题 题目1:下列选项描述错误的是? 选项: A Hadoop HA即集群中包含Secondary NameNode作为备份节点存在。 B ResourceManager负责的是整个Yarn集群资源的监控、分配和管理工作 C NodeManager负责定时的向ResourceManager汇报所在节点的资源使用情况…...

postman参数为D:\\audio\\test.mp3请求报错
报错信息 报错 java.lang.IllegalArgumentException: Invalid character found in the request target [/v1/audio/transcriptions?audioPathD:\\audio\\test.mp3 ]. The valid characters are defined in RFC 7230 and RFC 3986 解决方式 yml文件上放行指定字符 relaxed-pa…...

进行主从复制时出现的异常FATAL CONFIG FILE ERROR (Redis 6.2.6)Reading the configuration file
错误如下所示: FATAL CONFIG FILE ERROR (Redis 6.2.6) Reading the configuration file, at line 1 >>> include/myredis/redis.conf Bad directive or wrong number of arguments出现错误的原因是.conf文件中命令之间缺少空格,如下所示&…...

611.有效的三角形个数
1.题目解析 给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。 补充: 1.三角形的判断:假设有三条边按大小排序: 2.题目示例 示例 1: 输入: nums [2,2,3,4] 输出: 3 解释:有效的组合是: 2,3,4 (使用…...

超详细,使用JavaScript获取短信验证码
一、引言 短信验证码的重要性已经不言而喻,那么如何使用avaScript获取短信验证码呢?今天小编就整理了超详细的攻略,请各位看好~ 二、准备工作 1.注册短信服务提供商 注册并登录你的短信平台,然后获取AppID和AppKey,注册地址在代码里 2.创建验证码模版 三、实现步骤 …...

利用 Python 进行数据分析实验(七)
一、实验目的 使用Python解决问题 二、实验要求 自主编写并运行代码,按照模板要求撰写实验报告 三、实验步骤 操作书上第九章内容请画出如图2.png所示的图形通过编码获得fcity.jpg的手绘图像(如beijing.jpg所示) 四、实验结果 T2 &qu…...

前端小技巧: 写一个异步程序示例, 使用任务队列替代promise和async/await等语法糖
异步程序设定场景 1 )场景设定 可以使用懒人每做几件事,就要休息一会儿,并且不会影响做事的顺序这种场景来模拟定义单例名称为: lazyMan支持 sleep 和 eat 两个方法支持链式调用 2 ) 调用示例 const lm new LazyMan(www) lm.eat(苹果).…...

【Windows下】Eclipse 尝试 Mapreduce 编程
文章目录 配置环境环境准备连接 Hadoop查看 hadoop 文件 导入 Hadoop 包创建 MapReduce 项目测试 Mapreduce 编程代码注意事项常见报错 配置环境 环境准备 本次实验使用的 Hadoop 为 2.7.7 版本,实验可能会用到的文件 百度网盘链接:https://pan.baidu…...

Python---time库
目录 时间获取 时间格式化 程序计时 time库包含三类函数: 时间获取:time() ctime() gmtime() 时间格式化:strtime() strptime() 程序计时:sleep() perf_counter() 下面逐一介绍&#…...

unity 自由框选截图(两种方法,亲测有效)
提示:文章有错误的地方,还望诸位大神不吝指教! 文章目录 前言一、第一种方法(1)简介GL(2) GL 用法:(3)具体代码 二、第二种方法第一步:第二步第三…...

项目代码规范
editorconfig EditorConfig 是一种用于统一不同编辑器和 IDE 的代码风格的文件格式和插件,帮助开发人员在不同的编辑器和 IDE 中保持一致的代码风格,从而提高代码的可读性和可维护性 # EditorConfig is awesome: https://EditorConfig.org root true[…...

STM32的BKP与RTC简介
芯片的供电引脚 引脚表橙色的是芯片的供电引脚,其中VSS/VDD是芯片内部数字部分的供电,VSSA/VDDA是芯片内部模拟部分的供电,这4组以VDD开头的供电都是系统的主电源,正常使用时,全部都要接3.3V的电源上,VBAT是…...

11.Java安卓程序设计-基于SSM框架的Android平台健康管理系统的设计与实现
摘要 随着人们生活水平的提高和健康意识的增强,健康管理系统在日常生活中扮演着越来越重要的角色。本研究旨在设计并实现一款基于SSM框架的Android平台健康管理系统,为用户提供全面的健康监测和管理服务。 在需求分析阶段,我们明确了系统的…...

jetbrains卡顿(Pycharm等全家桶)终极解决方案,肯定解决!非常肯定!
话越短,越有用,一共四种方案,肯定能解决!!!非常肯定!! 下面四种解决方案,笔者按照实际体验后的结果,按照优先级从高到低排序。你只要按顺序试试就知道了。 m…...

c++的排序算法
一:merge 是 C STL 中的一个算法函数,用于将两个已排序的序列合并成一个有序序列。 template<class InputIterator1, class InputIterator2, class OutputIterator, class Compare> OutputIterator merge(InputIterator1 first1, InputIterator1 …...

YOLOv5独家原创改进:SPPF自研创新 | SPPF与感知大内核卷积UniRepLK结合,大kernel+非膨胀卷积提升感受野
💡💡💡本文自研创新改进:SPPF与感知大内核卷积UniRepLK结合,大kernel+非膨胀卷积,使SPPF增加大kernel,提升感受野,最终提升检测精度 收录 YOLOv5原创自研 https://blog.csdn.net/m0_63774211/category_12511931.html 💡💡💡全网独家首发创新(原创),…...

【C/PTA —— 15.结构体2(课外实践)】
C/PTA —— 15.结构体2(课外实践) 7-1 一帮一7-2 考试座位号7-3 新键表输出7-4 可怕的素质7-5 找出同龄者7-6 排队7-7 军训 7-1 一帮一 #include<stdio.h> #include<string.h>struct student {int a;char name[20]; };struct student1 {int …...

艾泊宇产品战略:适应新消费时代,产品战略指南以应对市场挑战和提升盈利
赚钱越来越难,这是许多企业和个人都感到困惑的问题。 然而,艾泊宇产品战略告诉大家,我们不能把这个问题简单地归咎于经济环境或市场竞争,而是需要从更深层次去思考和解决。 本文将从多个角度去剖析这个问题,并探讨在…...

使用autodl服务器,两个3090显卡上运行, Yi-34B-Chat-int4模型,并使用vllm优化加速,显存占用42G,速度23 words/s
1,演示视频地址 https://www.bilibili.com/video/BV1Hu4y1L7BH/ 使用autodl服务器,两个3090显卡上运行, Yi-34B-Chat-int4模型,用vllm优化,增加 --num-gpu 2,速度23 words/s 2,使用3090显卡 和…...

ORACLE数据库实验总集 实验六 SQL 语句应用
一、 实验目的 (1) 掌握数据的插入(INSERT)、 修改(UPDATE) 和删除(DELETE) 操作。 (2) 掌握不同类型的数据查询(SELECT) 操作。 二、…...

[FPGA 学习记录] 快速开发的法宝——IP核
快速开发的法宝——IP核 文章目录 1 IP 核是什么2 为什么要使用 IP 核3 IP 核的存在形式4 IP 核的缺点5 Quartus II 软件下 IP 核的调用6 Altera IP 核的分类 在本小节当中,我们来学习一下 IP 核的相关知识。 IP 核在 FPGA 开发当中应用十分广泛,它被称为…...

每日一题:LeetCode-11.盛水最多的容器
每日一题系列(day 13) 前言: 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🔎…...