- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章.NET Core对象池的应用:编程篇由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
借助于有效的自动化垃圾回收机制,.NET让开发人员不在关心对象的生命周期,但实际上很多性能问题都来源于GC。并不说.NET的GC有什么问题,而是对象生命周期的跟踪和管理本身是需要成本的,不论交给应用还是框架来做,都会对性能造成影响。在一些对性能比较敏感的应用中,我们可以通过对象复用的方式避免垃圾对象的产生,进而避免GC因对象回收导致的性能损失。对象池是对象复用的一种常用的方式。.NET提供了一个简单高效的对象池框架,并使用在ASP.NET自身框架中。这个对象池狂框架由“Microsoft.Extensions.ObjectPool”这个NuGet包提供,我们可以通过添加这个NuGet包它引入我们的应用中。接下来我们就通过一些简单的示例来演示一下对象池的基本编程模式.
。
和绝大部分的对象池编程方式一样,当我们需要消费某个对象的时候,我们不会直接创建它,而是选择从对象池中“借出”一个对象。一般来说,如果对象池为空,或者现有的对象都正在被使用,它会自动帮助我们完成对象的创建。借出的对象不再使用的时候,我们需要及时将其“归还”到对象池中以供后续复用。我们在使用.NET的对象池框架时,主要会使用如下这个ObjectPool<T>类型,针对池化对象的借与还体现在它的Get和Return方法中.
public abstract class ObjectPool<T> where T: class{ public abstract T Get(); public abstract void Return(T obj);}
我们接下来利用一个简单的控制台程序来演示对象池的基本编程模式。在添加了针对“Microsoft.Extensions.ObjectPool”这个NuGet包的引用之后,我们定义了如下这个FoobarService类型来表示希望池化复用的服务对象。如代码片段所示,FoobarService具有一个自增整数表示Id属性作为每个实例的唯一标识,静态字段_latestId标识当前分发的最后一个标识.
public class FoobarService{ internal static int _latestId; public int Id { get; } public FoobarService() => Id = Interlocked.Increment(ref _latestId);}
通过对象池的方式来使用FoobarService对象体现在如下的代码片段中。我们通过调用ObjectPool类型的静态方法Create<FoobarService>方法得到针对FoobarService类型的对象池,这是一个ObjectPool<FoobarService>对象。针对单个FoobarService对象的使用体现在本地方法ExecuteAsync中。如代码片段所示,我们调用ObjectPool<FoobarService>对象的Get方法从对象池中借出一个Foobar对象。为了确定对象是否真的被复用,我们在控制台上打印出对象的标识。我们通过延迟1秒钟模拟针对服务对象的长时间使用,并在最后通过调用ObjectPool<FoobarService>对象的Return方法将借出的对象释放到对象池中.
class Program{ static async Task Main() { var objectPool = ObjectPool.Create<FoobarService>(); while (true) { Console.Write("Used services: "); await Task.WhenAll(Enumerable.Range(1, 3).Select(_ => ExecuteAsync())); Console.Write("\n"); } async Task ExecuteAsync() { var service = objectPool.Get(); try { Console.Write($"{service.Id}; "); await Task.Delay(1000); } finally { objectPool.Return(service); } } }}
在Main方法中,我们构建了一个无限循环,并在每次迭代中并行执行ExecuteAsync方法三次。演示实例运行之后会在控制台上输出如下所示的结果,可以看出每轮迭代使用的三个对象都是一样的。每次迭代,它们从对象池中被借出,使用完之后又回到池中供下一次迭代使用.
。
我们知道依赖注入是已经成为 .NET Core的基本编程模式,针对对象池的编程最好也采用这样的编程方式。如果采用依赖注入,容器提供的并不是代表对象池的ObjectPool<T>对象,而是一个ObjectPoolProvider对象。顾名思义, ObjectPoolProvider对象作为对象池的提供者,用来提供针对指定对象类型的ObjectPool<T>对象.
.NET提供的大部分框架都提供了针对IServiceCollection接口的扩展方法来注册相应的服务,但是对象池框架并没有定义这样的扩展方法,所以我们需要采用原始的方式来完成针对ObjectPoolProvider的注册。如下面的代码片段所示,在创建出ServiceCollection对象之后,我们通过调用AddSingleton扩展方法注册了ObjectPoolProvider的默认实现类型DefaultObjectPoolProvider.
class Program{ static async Task Main() { var objectPool = new ServiceCollection().AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>() .BuildServiceProvider() .GetRequiredService<ObjectPoolProvider>() .Create<FoobarService>(); … }}
在利用ServiceCollection对象创建出代表依赖注入容器的IServiceProvider对象之后,我们利用它提取出ObjectPoolProvider对象,并通过调用其Create<T>方法得到表示对象池的ObjectPool<FoobarService>对象。改动的程序执行之后同样会在控制台输出如上图所示的结果.
。
通过前面的实例演示可以看出,对象池在默认情况下会帮助我们完成对象的创建工作。我们可以想得到,它会在对象池无可用对象的时候会调用默认的构造函数来创建提供的对象。如果池化对象类型没有默认的构造函数呢?或者我们希望执行一些初始化操作呢?
在另一方面,当不在使用的对象被归还到对象池之前,很有可能会执行一些释放性质的操作(比如集合对象在归还之前应该被清空)。还有一种可能是对象有可能不能再次复用(比如它内部维护了一个处于错误状态并无法恢复的网络连接),那么它就不能被释放会对象池。上述的这些需求都可以通过IPooledObjectPolicy<T>接口表示的池化对象策略来解决.
同样以我们演示实例中使用的FoobarService类型,如果并不希望用户直接调用构造函数来创建对应的实例,所以我们按照如下的方式将其构造函数改为私有,并定义了一个静态的工厂方法Create来创建FoobarService对象。当FoobarService类型失去了默认的无参构造函数之后,我们演示的程序将无法编译.
public class FoobarService{ internal static int _latestId; public int Id { get; } private FoobarService() => Id = Interlocked.Increment(ref _latestId); public static FoobarService Create() => new FoobarService();}
为了解决这个问题,我们为FoobarService类型定义一个代表池化对象策略的FoobarPolicy类型。如代码片段所示,FoobarPolicy类型实现了IPooledObjectPolicy<FoobarService>接口,实现的Create方法通过调用FoobarSerivice类型的静态同名方法完成针对对象的创建。另一个方法Return可以用来执行一些对象归还前的释放操作,它的返回值表示该对象还能否回到池中供后续使用。由于FoobarService对象可以被无限次复用,所以实现的Return方法直接返回True.
public class FoobarPolicy : IPooledObjectPolicy<FoobarService>{ public FoobarService Create() => FoobarService.Create(); public bool Return(FoobarService obj) => true;}
在调用ObjectPoolProvider对象的Create<T>方法针对指定的类型创建对应的对象池的时候,我们将一个IPooledObjectPolicy<T>对象作为参数,创建的对象池将会根据该对象定义的策略来创建和释放对象.
class Program{ static async Task Main() { var objectPool = new ServiceCollection().AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>() .BuildServiceProvider() .GetRequiredService<ObjectPoolProvider>() .Create(new FoobarPolicy()); … }}
。
对象池容纳对象的数量总归是有限的,默认情况下它的大小为当前机器处理器数量的2倍,这一点可以通过一个简单的实例来验证一下。如下面的代码片段所示,我们将演示程序中每次迭代并发执行ExecuteAsync方法的数量设置为当前机器处理器数量的2倍,并将最后一次创建的FoobarService对象的ID打印出来。为了避免控制台上的无效输出,我们将ExecuteAsync方法中的控制台输出代码移除.
class Program{ static async Task Main() { var objectPool = new ServiceCollection().AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>() .BuildServiceProvider() .GetRequiredService<ObjectPoolProvider>() .Create(new FoobarPolicy()); var poolSize = Environment.ProcessorCount * 2; while (true) { while (true) { await Task.WhenAll(Enumerable.Range(1, poolSize).Select(_ => ExecuteAsync())); Console.WriteLine($"Last service: {FoobarService._latestId}"); } } async Task ExecuteAsync() { var service = objectPool.Get(); try { await Task.Delay(1000); } finally { objectPool.Return(service); } } }}
上面这个演示实例表达的意思是:对象池的大小和对象消费率刚好是一致的。在这种情况下,消费的每一个对象都是从对象池中提取出来,并且能够成功还回去,那么对象的创建数量就是对象池的大小。下图所示的是演示程序运行之后再控制台上的输出结果,整个应用的生命周期范围内一共只会有16个对象被创建出来,因为我当前机器的处理器数量为8.
如果对象池的大小为当前机器处理器数量的2倍,那么我们倘若将对象的消费率提高,意味着池化的对象将无法满足消费需求,新的对象将持续被创建出来。为了验证我们的想法,我们按照如下的方式将每次迭代执行任务的数量加1.
class Program{ static async Task Main() { var objectPool = new ServiceCollection().AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>() .BuildServiceProvider() .GetRequiredService<ObjectPoolProvider>() .Create(new FoobarPolicy()); var poolSize = Environment.ProcessorCount * 2; while (true) { while (true) { await Task.WhenAll(Enumerable.Range(1, poolSize + 1) .Select(_ => ExecuteAsync())); Console.WriteLine($"Last service: {FoobarService._latestId}"); } } … }}
再次运行改动后的程序,我们会在控制台上看到如下图所示的输出结果。由于每次迭代针对对象的需求量是17,但是对象池只能提供16个对象,所以每次迭代都必须额外创建一个新的对象.
。
由于对象池容纳的对象数量是有限的,如果现有的所有对象已经被提取出来,它会提供一个新创建的对象。从另一方面讲,我们从对象池得到的对象在不需要的时候总是会还回去,但是对象池可能容不下那么多对象,它只能将其丢弃,被丢弃的对象将最终被GC回收。如果对象类型实现了IDisposable接口,在它不能回到对象池的情况下,它的Dispose方法应该被立即执行.
为了验证不能正常回归对象池的对象能否被及时释放,我们再次对演示的程序作相应的修改。我们让FoobarService类型实现IDisposable接口,并在实现的Dispose方法中将自身ID输出到控制台上。然后我们按照如下的方式以每次迭代并发量高于对象池大小的方式消费对象.
class Program{ static async Task Main() { var objectPool = new ServiceCollection().AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>() .BuildServiceProvider() .GetRequiredService<ObjectPoolProvider>() .Create(new FoobarPolicy()); while (true) { Console.Write("Disposed services:"); await Task.WhenAll(Enumerable.Range(1, Environment.ProcessorCount * 2 + 3).Select(_ => ExecuteAsync())); Console.Write("\n"); } async Task ExecuteAsync() { var service = objectPool.Get(); try { await Task.Delay(1000); } finally { objectPool.Return(service); } } }}public class FoobarService: IDisposable{ internal static int _latestId; public int Id { get; } private FoobarService() => Id = Interlocked.Increment(ref _latestId); public static FoobarService Create() => new FoobarService(); public void Dispose() => Console.Write($"{Id}; ");}
演示程序运行之后会在控制台上输出如下图所示的结果,可以看出对于每次迭代消费的19个对象,只有16个能够正常回归对象池,有三个将被丢弃并最终被GC回收。由于这样的对象将不能被复用,它的Dispose方法会被调用,我们定义其中的释放操作得以被及时执行.
.NET Core对象池的应用:设计篇 .NET Core对象池的应用:扩展篇 。
到此这篇关于.NET Core对象池的应用:编程篇的文章就介绍到这了,更多相关.NET Core对象池的应用内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://www.cnblogs.com/artech/p/object-pool-01.html 。
最后此篇关于.NET Core对象池的应用:编程篇的文章就讲到这里了,如果你想了解更多关于.NET Core对象池的应用:编程篇的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我的一位教授给了我们一些考试练习题,其中一个问题类似于下面(伪代码): a.setColor(blue); b.setColor(red); a = b; b.setColor(purple); b
我似乎经常使用这个测试 if( object && object !== "null" && object !== "undefined" ){ doSomething(); } 在对象上,我
C# Object/object 是值类型还是引用类型? 我检查过它们可以保留引用,但是这个引用不能用于更改对象。 using System; class MyClass { public s
我在通过 AJAX 发送 json 时遇到问题。 var data = [{"name": "Will", "surname": "Smith", "age": "40"},{"name": "Wil
当我尝试访问我的 View 中的对象 {{result}} 时(我从 Express js 服务器发送该对象),它只显示 [object][object]有谁知道如何获取 JSON 格式的值吗? 这是
我有不同类型的数据(可能是字符串、整数......)。这是一个简单的例子: public static void main(String[] args) { before("one"); }
嗨,我是 json 和 javascript 的新手。 我在这个网站找到了使用json数据作为表格的方法。 我很好奇为什么当我尝试使用 json 数据作为表时,我得到 [Object,Object]
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
我听别人说 null == object 比 object == null check 例如: void m1(Object obj ) { if(null == obj) // Is thi
Match 对象 提供了对正则表达式匹配的只读属性的访问。 说明 Match 对象只能通过 RegExp 对象的 Execute 方法来创建,该方法实际上返回了 Match 对象的集合。所有的
Class 对象 使用 Class 语句创建的对象。提供了对类的各种事件的访问。 说明 不允许显式地将一个变量声明为 Class 类型。在 VBScript 的上下文中,“类对象”一词指的是用
Folder 对象 提供对文件夹所有属性的访问。 说明 以下代码举例说明如何获得 Folder 对象并查看它的属性: Function ShowDateCreated(f
File 对象 提供对文件的所有属性的访问。 说明 以下代码举例说明如何获得一个 File 对象并查看它的属性: Function ShowDateCreated(fil
Drive 对象 提供对磁盘驱动器或网络共享的属性的访问。 说明 以下代码举例说明如何使用 Drive 对象访问驱动器的属性: Function ShowFreeSpac
FileSystemObject 对象 提供对计算机文件系统的访问。 说明 以下代码举例说明如何使用 FileSystemObject 对象返回一个 TextStream 对象,此对象可以被读
我是 javascript OOP 的新手,我认为这是一个相对基本的问题,但我无法通过搜索网络找到任何帮助。我是否遗漏了什么,或者我只是以错误的方式解决了这个问题? 这是我的示例代码: functio
我可以很容易地创造出很多不同的对象。例如像这样: var myObject = { myFunction: function () { return ""; } };
function Person(fname, lname) { this.fname = fname, this.lname = lname, this.getName = function()
任何人都可以向我解释为什么下面的代码给出 (object, Object) 吗? (console.log(dope) 给出了它应该的内容,但在 JSON.stringify 和 JSON.parse
我正在尝试完成散点图 exercise来自免费代码营。然而,我现在只自己学习了 d3 几个小时,在遵循 lynda.com 的教程后,我一直在尝试确定如何在工具提示中显示特定数据。 This code
我是一名优秀的程序员,十分优秀!