.NET Core中如何實(shí)現(xiàn)或使用對(duì)象池?
前言
池這個(gè)概念大家都很熟悉,比如我們經(jīng)常聽到數(shù)據(jù)庫連接池和線程池。它是一種基于使用預(yù)先分配資源集合的性能優(yōu)化思想。
簡(jiǎn)單說,對(duì)象池就是對(duì)象的容器,旨在優(yōu)化資源的使用,通過在一個(gè)容器中池化對(duì)象,并根據(jù)需要重復(fù)使用這些池化對(duì)象來滿足性能上的需求。當(dāng)一個(gè)對(duì)象被激活時(shí),便被從池中取出。當(dāng)對(duì)象被停用時(shí),它又被放回池中,等待下一個(gè)請(qǐng)求。對(duì)象池一般用于對(duì)象的初始化過程代價(jià)較大或使用頻率較高的場(chǎng)景。
那在 .NET 中如何實(shí)現(xiàn)或使用對(duì)象池呢?
在 ASP.NET Core 框架里已經(jīng)內(nèi)置了一個(gè)對(duì)象池功能的實(shí)現(xiàn):Microsoft.Extensions.ObjectPool。如果是控制臺(tái)應(yīng)用程序,可以單獨(dú)安裝這個(gè)擴(kuò)展庫。
池化策略
首先,要使用 ObjectPool,需要?jiǎng)?chuàng)建一個(gè)池化策略,告訴對(duì)象池你將如何創(chuàng)建對(duì)象,以及如何歸還對(duì)象。
該策略通過實(shí)現(xiàn)接口 IPooledObjectPolicy 來定義,下面是一個(gè)最簡(jiǎn)單的策略實(shí)現(xiàn):
public class FooPooledObjectPolicy : IPooledObjectPolicy<Foo> { public Foo Create() { return new Foo(); } public bool Return(Foo obj) { return true; } }
如果每次編碼都要定義這樣的策略,會(huì)比較麻煩,可以自己定義一個(gè)通用的泛型實(shí)現(xiàn)。Microsoft.Extensions.ObjectPool 中也提供了一個(gè)默認(rèn)的泛型實(shí)現(xiàn):DefaultPooledObjectPolicy<T>。如果不需要定義復(fù)雜的構(gòu)造邏輯,使用默認(rèn)的就行。下面我們來看看怎么使用。
對(duì)象池的使用
對(duì)象池使用的原則是:有借有還,再借不難。
當(dāng)對(duì)象池中沒有實(shí)例時(shí),則創(chuàng)建實(shí)例并返回給調(diào)用組件;當(dāng)對(duì)象池中已有實(shí)例時(shí),則直接取一個(gè)現(xiàn)有實(shí)例返回給調(diào)用組件。而且這個(gè)過程是線程安全的。
Microsoft.Extensions.ObjectPool 提供了默認(rèn)的對(duì)象池實(shí)現(xiàn):DefaultObjectPool<T>,它提供了借 Get 和還 Return 操作接口。創(chuàng)建對(duì)象池時(shí)需要提供池化策略 IPooledObjectPolicy<T> 作為其構(gòu)造參數(shù)。
var policy = new DefaultPooledObjectPolicy<Foo>(); var pool = new DefaultObjectPool<Foo>(policy);
我們來看一個(gè)常規(guī)示例(C# 9.0 單文件完整代碼):
using Microsoft.Extensions.ObjectPool; using System; var policy = new DefaultPooledObjectPolicy<Foo>(); var pool = new DefaultObjectPool<Foo>(policy); // 借 var item1 = pool.Get(); // 還 pool.Return(item1); Console.WriteLine("item 1: {0}", item1.Id); // 借 var item2 = pool.Get(); // 還 pool.Return(item2); Console.WriteLine("item 2: {0}", item2.Id); Console.ReadKey(); public class Foo { public string Id { get; set; } = Guid.NewGuid().ToString("N"); }
打印結(jié)果:
通過打印的 Id 知道,item1 和 item2 是同一樣對(duì)象。
我們?cè)賮砜纯粗唤璨贿€會(huì)是什么樣子:
// ... // 借 var item1 = pool.Get(); Console.WriteLine("item 1: {0}", item1.Id); // 再借 var item2 = pool.Get(); Console.WriteLine("item 2: {0}", item2.Id); // ...
打印結(jié)果:
可以看到,兩個(gè)對(duì)象是不同的實(shí)例。所以,當(dāng)調(diào)用組件從對(duì)象池中借走一個(gè)對(duì)象實(shí)例,使用完后應(yīng)立即歸還給對(duì)象池,以便重復(fù)使用,避免因構(gòu)造新對(duì)象消耗過多資源。
指定對(duì)象池容量
在創(chuàng)建 DefaultObjectPool<T> 時(shí),還可以指定第二個(gè)參數(shù):對(duì)象池的容量。它表示最大可從該對(duì)象池取出的對(duì)象數(shù)量,指定數(shù)量以外的被取走的對(duì)象將不會(huì)被池化。我來演示一下,大家就知道什么意思了,請(qǐng)看示例:
using Microsoft.Extensions.ObjectPool; using System; var policy = new DefaultPooledObjectPolicy<Foo>(); // 指定容量為 2。 var pool = new DefaultObjectPool<Foo>(policy, 2); // 借走 3 個(gè) var item1 = pool.Get(); Console.WriteLine("item 1: {0}", item1.Id); var item2 = pool.Get(); Console.WriteLine("item 2: {0}", item2.Id); var item3 = pool.Get(); Console.WriteLine("item 3: {0}", item3.Id); // 再還會(huì) 3 個(gè) pool.Return(item1); pool.Return(item2); pool.Return(item3); // 再借走 3 個(gè) var item4 = pool.Get(); Console.WriteLine("item 4: {0}", item4.Id); var item5 = pool.Get(); Console.WriteLine("item 5: {0}", item5.Id); var item6 = pool.Get(); Console.WriteLine("item 6: {0}", item6.Id); Console.ReadKey();
注意示例代碼中我給對(duì)象池指定了容量為 2,然后借走 3 個(gè)再歸還 3 個(gè),后面再借走 3 個(gè)。來看看打印結(jié)果:
我們看到,item1 與 item4 是同一個(gè)對(duì)象,item2 與 item5 是同一個(gè)對(duì)象。item3 與 item6 卻不是同一個(gè)對(duì)象。
也就是說,當(dāng)對(duì)象從池中取出超過指定容量的對(duì)象數(shù)量,雖然歸還了相同數(shù)量的對(duì)象,但對(duì)象池只允許容納 2 個(gè)對(duì)象,第三個(gè)對(duì)象不會(huì)被池化。
在 ASP.NET Core 中使用
ASP.NET Core 框架內(nèi)置好了 Microsoft.Extensions.ObjectPool,不需要單獨(dú)安裝。官方文檔有個(gè)基于 ASP.NET Core 的使用示例:
https://docs.microsoft.com/en-us/aspnet/core/performance/objectpool
這個(gè)例子把 StringBuilder 做了池化。我這里就直接貼官方的例子了,為了更直觀些,我把無關(guān)的代碼簡(jiǎn)化掉了。
先定義一個(gè)中間件:
public class BirthdayMiddleware { private readonly RequestDelegate _next; public BirthdayMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context, ObjectPool<StringBuilder> builderPool) { var stringBuilder = builderPool.Get(); try { stringBuilder.Append("Hi"); // 其它處理 await context.Response.WriteAsync(stringBuilder.ToString()); } finally // 即使出錯(cuò)也要保證歸還對(duì)象 { builderPool.Return(stringBuilder); } } }
在 Startup 中注冊(cè)相應(yīng)的服務(wù)和中間件:
public class Startup { public void ConfigureServices(IServiceCollection services) { services.TryAddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>(); services.TryAddSingleton<ObjectPool<StringBuilder>>(serviceProvider => { var provider = serviceProvider.GetRequiredService<ObjectPoolProvider>(); var policy = new StringBuilderPooledObjectPolicy(); return provider.Create(policy); }); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseMiddleware<BirthdayMiddleware>(); } }
這個(gè)示例用了 DefaultObjectPoolProvider,它是默認(rèn)的對(duì)象池 Provider,所以你也可以自定義自己的對(duì)象池 Provider。
總結(jié)
Microsoft.Extensions.ObjectPool 提供的對(duì)象池功能還是挺靈活的。普通場(chǎng)景使用使用默認(rèn)的池化策略、默認(rèn)的對(duì)象池和默認(rèn)的對(duì)象池提供者就可以滿足需求,也可以自定義其中任意某部件來實(shí)現(xiàn)比較特殊或復(fù)雜的需求。
對(duì)象池的使用原則是:有借有還,再借不難。當(dāng)調(diào)用組件從對(duì)象池中借走一個(gè)對(duì)象實(shí)例,使用完后應(yīng)立即歸還給對(duì)象池,以便重復(fù)利用,避免因過多的對(duì)象初始化影響系統(tǒng)性能。
到此這篇關(guān)于.NET Core中如何實(shí)現(xiàn)或使用對(duì)象池的文章就介紹到這了,更多相關(guān).NET Core使用對(duì)象池內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Asp.net操作Excel更輕松的實(shí)現(xiàn)代碼
今天先介紹一個(gè)關(guān)于導(dǎo)出數(shù)據(jù)的例子,以Excel為模板。直接進(jìn)入正題了2011-10-10.net中實(shí)現(xiàn)listBox左右移動(dòng)
這里給大家推薦的是一段網(wǎng)友分享的,使用.net實(shí)現(xiàn)listBox左右移動(dòng)的代碼,簡(jiǎn)單實(shí)用,這里記錄下來,有需要的小伙伴參考下吧。2015-03-03asp.net(C#)函數(shù)對(duì)象參數(shù)傳遞的問題
我們知道在.net里class是引用類型,在函數(shù)參數(shù)表中的對(duì)象傳遞的都是對(duì)象的引用,所以在函數(shù)體內(nèi)對(duì)其對(duì)象參數(shù)的修改會(huì)影響函數(shù)外對(duì)應(yīng)的對(duì)象本身,例如下面的程序.2009-12-12.net后臺(tái)代碼調(diào)用前臺(tái)JS的兩種方式
這篇文章主要介紹了.net后臺(tái)代碼調(diào)用前臺(tái)JS的兩種方式,需要的朋友可以參考下2014-03-03asp.net 1.1/ 2.0 中快速實(shí)現(xiàn)單點(diǎn)登陸
asp.net 1.1/ 2.0 中快速實(shí)現(xiàn)單點(diǎn)登陸...2007-04-04.Net Compact Framework開發(fā)小技巧 推薦
這篇文章對(duì)于.Net Compact Framework開發(fā)的朋友有一定的幫助,內(nèi)容比較實(shí)用。2009-02-02如何在ASP.NET Core中使用HttpClientFactory
這篇文章主要介紹了如何在ASP.NET Core中使用HttpClientFactory,幫助大家更好的理解和學(xué)習(xí)使用.net技術(shù),感興趣的朋友可以了解下2021-04-04ASP.NET MVC3關(guān)于生成純靜態(tài)后如何不再走路由直接訪問靜態(tài)頁面
高訪問量類型的電子商務(wù)網(wǎng)站,需要將一些不是經(jīng)常變化的頁面生成靜態(tài)頁面,然后普通用戶就可以直接訪問這些靜態(tài)頁面而不用再訪問需要連接數(shù)據(jù)庫的動(dòng)態(tài)頁面。那么ASP.NET MVC3中如何做到這一點(diǎn)呢2011-12-12Asp.Net Core實(shí)現(xiàn)Excel導(dǎo)出功能的實(shí)現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于Asp.Net Core實(shí)現(xiàn)Excel導(dǎo)出功能的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12