.NET Core中如何實現或使用對象池?

 更新時間:2021年07月12日 11:44:09   作者:精致碼農  
什么是對象池?簡單來說它就是一種為對象提供可復用性能力的軟件設計思路,對象池就是通過“借”和“還”這樣兩個動作來保證對象可以被重復使用,這篇文章主要給大家介紹了關于.NET Core中如何實現或使用對象池的相關資料,需要的朋友可以參考下

前言

池這個概念大家都很熟悉,比如我們經常聽到數據庫連接池和線程池。它是一種基于使用預先分配資源集合的性能優化思想。

簡單說,對象池就是對象的容器,旨在優化資源的使用,通過在一個容器中池化對象,并根據需要重復使用這些池化對象來滿足性能上的需求。當一個對象被激活時,便被從池中取出。當對象被停用時,它又被放回池中,等待下一個請求。對象池一般用于對象的初始化過程代價較大或使用頻率較高的場景。

那在 .NET 中如何實現或使用對象池呢?

在 ASP.NET Core 框架里已經內置了一個對象池功能的實現:Microsoft.Extensions.ObjectPool。如果是控制臺應用程序,可以單獨安裝這個擴展庫。

池化策略

首先,要使用 ObjectPool,需要創建一個池化策略,告訴對象池你將如何創建對象,以及如何歸還對象。

該策略通過實現接口 IPooledObjectPolicy 來定義,下面是一個最簡單的策略實現:

public class FooPooledObjectPolicy : IPooledObjectPolicy<Foo>
{
    public Foo Create()
    {
        return new Foo();
    }

    public bool Return(Foo obj)
    {
        return true;
    }
}

如果每次編碼都要定義這樣的策略,會比較麻煩,可以自己定義一個通用的泛型實現。Microsoft.Extensions.ObjectPool 中也提供了一個默認的泛型實現:DefaultPooledObjectPolicy<T>。如果不需要定義復雜的構造邏輯,使用默認的就行。下面我們來看看怎么使用。

對象池的使用

對象池使用的原則是:有借有還,再借不難。

當對象池中沒有實例時,則創建實例并返回給調用組件;當對象池中已有實例時,則直接取一個現有實例返回給調用組件。而且這個過程是線程安全的。

Microsoft.Extensions.ObjectPool 提供了默認的對象池實現:DefaultObjectPool<T>,它提供了借 Get 和還 Return 操作接口。創建對象池時需要提供池化策略 IPooledObjectPolicy<T> 作為其構造參數。

var policy = new DefaultPooledObjectPolicy<Foo>();
var pool = new DefaultObjectPool<Foo>(policy);

我們來看一個常規示例(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");
}

打印結果:

通過打印的 Id 知道,item1 和 item2 是同一樣對象。

我們再來看看只借不還會是什么樣子:

// ...

// 借
var item1 = pool.Get();
Console.WriteLine("item 1: {0}", item1.Id);

// 再借
var item2 = pool.Get();
Console.WriteLine("item 2: {0}", item2.Id);

// ...

打印結果:

可以看到,兩個對象是不同的實例。所以,當調用組件從對象池中借走一個對象實例,使用完后應立即歸還給對象池,以便重復使用,避免因構造新對象消耗過多資源。

指定對象池容量

在創建 DefaultObjectPool<T> 時,還可以指定第二個參數:對象池的容量。它表示最大可從該對象池取出的對象數量,指定數量以外的被取走的對象將不會被池化。我來演示一下,大家就知道什么意思了,請看示例:

using Microsoft.Extensions.ObjectPool;
using System;

var policy = new DefaultPooledObjectPolicy<Foo>();

// 指定容量為 2。
var pool = new DefaultObjectPool<Foo>(policy, 2);

// 借走 3 個
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);

// 再還會 3 個
pool.Return(item1);
pool.Return(item2);
pool.Return(item3);


// 再借走 3 個
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();

注意示例代碼中我給對象池指定了容量為 2,然后借走 3 個再歸還 3 個,后面再借走 3 個。來看看打印結果:

我們看到,item1 與 item4 是同一個對象,item2 與 item5 是同一個對象。item3 與 item6 卻不是同一個對象。

也就是說,當對象從池中取出超過指定容量的對象數量,雖然歸還了相同數量的對象,但對象池只允許容納 2 個對象,第三個對象不會被池化。

在 ASP.NET Core 中使用

ASP.NET Core 框架內置好了 Microsoft.Extensions.ObjectPool,不需要單獨安裝。官方文檔有個基于 ASP.NET Core 的使用示例:

https://docs.microsoft.com/en-us/aspnet/core/performance/objectpool

這個例子把 StringBuilder 做了池化。我這里就直接貼官方的例子了,為了更直觀些,我把無關的代碼簡化掉了。

先定義一個中間件:

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 // 即使出錯也要保證歸還對象
        {
            builderPool.Return(stringBuilder);
        }
    }
}

在 Startup 中注冊相應的服務和中間件:

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>();
    }
}

這個示例用了 DefaultObjectPoolProvider,它是默認的對象池 Provider,所以你也可以自定義自己的對象池 Provider。

總結

Microsoft.Extensions.ObjectPool 提供的對象池功能還是挺靈活的。普通場景使用使用默認的池化策略、默認的對象池和默認的對象池提供者就可以滿足需求,也可以自定義其中任意某部件來實現比較特殊或復雜的需求。

對象池的使用原則是:有借有還,再借不難。當調用組件從對象池中借走一個對象實例,使用完后應立即歸還給對象池,以便重復利用,避免因過多的對象初始化影響系統性能。

到此這篇關于.NET Core中如何實現或使用對象池的文章就介紹到這了,更多相關.NET Core使用對象池內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • MVC框架是什么 這里為你解答

    MVC框架是什么 這里為你解答

    MVC是一個設計模式,它強制性的使應用程序的輸入、處理和輸出分開。這篇文章為大家詳細介紹了MVC框架是什么,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • asp.net下降文本格式數據導入到數據庫中的代碼

    asp.net下降文本格式數據導入到數據庫中的代碼

    導入文本格式數據到數據庫中的代碼,需要的朋友可以參考下。
    2010-05-05
  • ASP.NET將Session保存到數據庫中的方法

    ASP.NET將Session保存到數據庫中的方法

    因為ASP.NET中Session的存取機制與ASP相同,都是保存在進行中, 一旦進程崩潰,所有Session信息將會丟失,所以我采取了將Session信息保存到SQL Server中,盡管還有其它的
    2013-08-08
  • ASP.NET如何獲取兩個日期之間的天數

    ASP.NET如何獲取兩個日期之間的天數

    這篇文章主要介紹了ASP.NET獲取兩個日期之間的天數方法,需要的朋友可以參考下
    2014-03-03
  • ASP.NET MVC中異常處理&自定義錯誤頁詳析

    ASP.NET MVC中異常處理&自定義錯誤頁詳析

    當ASP.NET MVC程序出現了異常,怎么處理更加規范?下面這篇文章主要給大家介紹了關于ASP.NET MVC中異常處理&自定義錯誤頁的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起學習學習吧。
    2018-04-04
  • ASP.NET WebAPI2復雜請求跨域設置的方法介紹

    ASP.NET WebAPI2復雜請求跨域設置的方法介紹

    這篇文章主要給大家介紹了關于ASP.NET WebAPI2復雜請求跨域設置的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者使用ASP.NET具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2020-07-07
  • Asp.Net Core 調用第三方Open API查詢物流數據的示例

    Asp.Net Core 調用第三方Open API查詢物流數據的示例

    這篇文章主要介紹了Asp.Net Core 調用第三方Open API查詢物流數據的示例,幫助大家更好的理解和學習使用Asp.Net Core,感興趣的朋友可以了解下
    2021-03-03
  • ASP.NET通過Remoting service上傳文件

    ASP.NET通過Remoting service上傳文件

    ASP.NET通過Remoting service上傳文件...
    2006-09-09
  • asp.net部署到IIS常見問題的解決方法

    asp.net部署到IIS常見問題的解決方法

    這篇文章主要為大家詳細介紹了asp.net部署到IIS常見問題的解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • VS 2015開發跨平臺手機應用的配置教程

    VS 2015開發跨平臺手機應用的配置教程

    這篇文章主要給大家介紹了關于VS 2015開發跨平臺手機應用配置的相關資料,文中通過圖文介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2017-12-12

最新評論

精品国内自产拍在线观看