溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

.NET?Core中對象池Object?Pool的使用方法是什么

發(fā)布時間:2021-11-22 15:45:08 來源:億速云 閱讀:114 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“.NET Core中對象池Object Pool的使用方法是什么”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“.NET Core中對象池Object Pool的使用方法是什么”吧!

一、什么是對象池

對象池簡單來說就是一種為對象提供可復(fù)用能力的軟件設(shè)計思路。我們常說有借有還,再借不難,而對象池就是通過借和還這樣兩個動作來保證對象可以被重復(fù)使用,從而節(jié)省頻繁創(chuàng)建對象的性能開銷。對象池最常用的場景是游戲設(shè)計,因為在游戲中大量存在著可復(fù)用的對象,源源不斷的子彈出現(xiàn)并不是循環(huán)再生的。在數(shù)據(jù)庫中存在著被稱為連接池的東西,每當(dāng)出現(xiàn)數(shù)據(jù)庫無法連接的情況時,經(jīng)驗豐富的開發(fā)人員往往會先檢查連接池是否滿了,這其實就是對象池模式在特定領(lǐng)域的具體實現(xiàn)。因此對象池本質(zhì)上就是負(fù)責(zé)一組對象創(chuàng)建和銷毀的容器。 對象池最大的優(yōu)勢是可以自主地管理池子內(nèi)的每個對象,決定它們是需要被回收還是可以重復(fù)使用。我們都知道創(chuàng)建一個新對象需要消耗一定的系統(tǒng)資源,一旦這些對象可以重復(fù)地使用就可以節(jié)省系統(tǒng)資源開銷,這對提高系統(tǒng)性能會非常有幫助。下面的代碼實微軟官方文檔實現(xiàn)的一個簡單的對象池:


public class ObjectPool<T> : IObjectPool<T>

{

	private Func<T> _instanceFactory;

	private ConcurrentBag<T> _instanceItems;

	public ObjectPool(Func<T> instanceFactory)

	{

		_instanceFactory = instanceFactory ?? 

		throw new ArgumentNullException(nameof(instanceFactory));

		_instanceItems = new ConcurrentBag<T>();

	}

	public T Get()

	{

		T item;

		if (_instanceItems.TryTake(out item)) return item;

		return _instanceFactory();

	}

	public void Return(T item)

	{

		_instanceItems.Add(item);

	}

}

二、.NET Core 中的對象池

.NET Core 中微軟已經(jīng)為我們提供了對象池的實現(xiàn),即Microsoft.Extensions.ObjectPool。它主要提供了三個核心的組件,分別是ObjectPoolObjectPoolProviderIPooledObjectPolicy。ObjectPool是一個抽象類,對外提供了Get和Return兩個方法,這就是所謂的有借有還。ObjectPoolProvider同樣是一個抽象類,它的職責(zé)就是創(chuàng)建ObjectPool,它提供了兩個Create方法,兩者的區(qū)別是無參數(shù)版本本質(zhì)上使用的是DefaultPooledObjectPolicy。它和DefaultObjectPool、DefaultObjectPoolProvider都是微軟提供的默認(rèn)實現(xiàn),IPooledObjectPolicy可以為不同的對象池定義不同的策略,來決定對象如何借、是否可以還。DefaultObjectPool內(nèi)部使用ObjectWrapper[]來管理對象,ObjectWrapper[]的大小等于 maximumRetained-1,默認(rèn)情況下maximumRetained等于Environment.ProcessorCount * 2,這里主要用到了Interlocked.CompareExchange()方法,

具體代碼如下:

public override T Get()

{

  var item = _firstItem;

  if (item == null || Interlocked.CompareExchange(ref _firstItem, null, item) != item)

  {

    var items = _items;

    for (var i = 0; i < items.Length; i++)

    {

      item = items[i].Element;

      if (item != null && Interlocked.CompareExchange(ref items[i].Element, null, item) == item)

      {

        return item;

      }

    }

    item = Create();

  }

  return item;

}

// Non-inline to improve its code quality as uncommon path

[MethodImpl(MethodImplOptions.NoInlining)]

private T Create() => _fastPolicy?.Create() ?? _policy.Create();



public override void Return(T obj)

{

  if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj)))

  {

    if (_firstItem != null || Interlocked.CompareExchange(ref _firstItem, obj, null) != null)

    {

      var items = _items;

      for (var i = 0; i < items.Length && Interlocked.CompareExchange(ref items[i].Element, obj, null) != null; ++i)

      {

      }

    }

  }

}

這里用到Interlocked.CompareExchange()方法,Get()方法將items[i].Elementnull進行交換,將指定元素設(shè)為 null 并返回原始值。Return()方法將items[i].Element和obj交換后的值不為 null,表示指定元素已經(jīng)歸還,這個方法只有在第一個參數(shù)和第三個參數(shù)相等時才會發(fā)生交換。

說了這么多,我們來看一下對象池具體的用法:

var service = new ServiceCollection();

//使用DefaultObjectPoolProvider

service.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();

//使用默認(rèn)策略

service.AddSingleton<ObjectPool<Foo>>(serviceProvider =>

{

  var objectPoolProvider = serviceProvider.GetRequiredService<ObjectPoolProvider>();

  return objectPoolProvider.Create<Foo>();

});

//使用自定義策略

service.AddSingleton<ObjectPool<Foo>>(serviceProvider =>

{

  var objectPoolProvider = serviceProvider.GetRequiredService<ObjectPoolProvider>();

  return objectPoolProvider.Create(new FooObjectPoolPolicy());

});



var serviceProvider = _service.BuildServiceProvider();



var objectPool = _serviceProvider.GetService<ObjectPool<Foo>>();



//有借有還,兩次是同一個對象

var item1 = objectPool.Get();

objectPool.Return(item1);

var item2 = objectPool.Get();

Assert.AreEqual(item1, item2);//true



//有借無還,兩次是不同的對象

var item3 = objectPool.Get();

var item4 = objectPool.Get();

Assert.AreEqual(item3, item4);//false

上面的代碼中Foo和FooObjectPoolPolicy是兩個工具類:

public class Foo

{

  public string Id { get; set; }

  public DateTime? CreatedAt { get; set; }

  public string CreatedBy { get; set; }

}



public class FooObjectPoolPolicy : IPooledObjectPolicy<Foo>

{

  public Foo Create()

  {

    return new Foo()

    {

      Id = Guid.NewGuid().ToString("N"),

      CreatedAt = DateTime.Now,

      CreatedBy = "zs"

    };

  }



  public bool Return(Foo obj)

  {

    return true;

  }

}

TIP:當(dāng)你需要控制對象池內(nèi)的對象如何被創(chuàng)建的時候,你可以考慮實現(xiàn)自定義的IPooledObjectPolicy<T>,反之DefaultPooledObjectPolicy<T>實現(xiàn)完全可以滿足你的使用。

感謝各位的閱讀,以上就是“.NET Core中對象池Object Pool的使用方法是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對.NET Core中對象池Object Pool的使用方法是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI