2009-11-04 65 views
16

我有一個在時間和內存方面構建起來很昂貴的類。我想保留這些東西,並在需要時將它們分配到同一進程中的多個線程。是否有.NET的通用對象池?

是否有一個通用的對象池已經過測試和驗證? (我不想COM +池。)

回答

5

沒有Cheeso,沒有一般對象池這樣。但這是一個好主意。我認爲這將是非常簡單的發展。關鍵是讓它在一個線程環境中運行良好。

我認爲這是一個有趣的設計問題。例如,如果這需要在大規模的服務器級別的硬件 - 和 - 你會給對象indivudual線程經常那麼你可以這樣做:

  1. 保留對象的單一的中央游泳池。
  2. 保留一個線程池(一個緩存),當它第一次爲一個線程調用時,以及它變爲空時,它將被填充。

這樣就避免了大多數請求的每線程爭用。

不同的操作條件會導致您不同的設計。例如,如果對象分配很少或者線程數量很少,那麼只需對集合進行鎖定可能會更簡單。這不會很好地擴展,但在這種情況下,它需要。

如果您正確設計類或接口,那麼您可以隨時改變實現來處理更復雜的場景。

1

爲什麼不寫一個單例,它只是作爲已經創建的對象數組的網關。

當一個對象被分發時,然後將它從可用列表中刪除,將其放入檢出列表中,然後在返回時將其反轉。

通過爲此使用一個單例,您有一個要調用的所有東西的靜態類,如果昂貴的類是單例的內部類,那麼沒有其他東西可以創建昂貴的類,並且您可以控制有多少個對象輕鬆創建。

+0

那麼雅,這將工作。一個對象池可以非常簡單。但是接下來還有更多的細節,比如有界對象總體(不低於x,不高於y),命名對象,對象屬性等等。我只是想知道是否有人設計過它並考慮過這些事情。 – Cheeso

+0

@Cheeso - 您可能想將其添加到您的問題中,因爲它會改變相當多的問題。 –

21

從MSDN拉直,這裏是在.NET 4中使用新的併發收集類型之一的例子:

下面的例子演示如何實現與System.Collections.Concurrent.ConcurrentBag<T>作爲其後備存儲的對象池。

public class ObjectPool<T> 
{ 
    private ConcurrentBag<T> _objects; 
    private Func<T> _objectGenerator; 

    public ObjectPool(Func<T> objectGenerator) 
    { 
     if (objectGenerator == null) 
      throw new ArgumentNullException("objectGenerator"); 
     _objects = new ConcurrentBag<T>(); 
     _objectGenerator = objectGenerator; 
    } 

    public T GetObject() 
    { 
     T item; 
     if (_objects.TryTake(out item)) 
      return item; 
     return _objectGenerator(); 
    } 

    public void PutObject(T item) 
    { 
     _objects.Add(item); 
    } 
} 
+1

謝謝你,我看到了這一個。它依賴於.NET 4.0。不幸的是,我依賴於NET 2.0。 ! – Cheeso

+1

鏈接,也許:[如何:使用ConcurrentBag創建對象池](http://msdn.microsoft.com/en-us/library/ff458671%28v=vs.110%29.aspx) –

6

280Z28提出的ObjectPool類看起來不錯。您也可以考慮創建另一個實現IDisposable的類並封裝GetObject()的返回值。這將確保對象返回到您的池並讀取很好:

class ObjectPoolReference<T> : IDisposable 
{ 
    public ObjectPool<T> Pool { get; private set; } 

    public T Instance { get; private set; } 

    public ObjectPoolReference(ObjectPool<T> pool, T instance) 
    { 
     Pool = pool; 
     Instance = instance; 
    } 

    ~ObjectPoolReference() 
    { 
     Dispose(); 
    } 

    #region IDisposable Members 

    private bool _Disposed = false; 

    public void Dispose() 
    { 
     if (!_Disposed) 
     { 
      Pool.PutObject(Instance); 

      _Disposed = true; 
     } 
    } 

    #endregion 
} 

//instance of the pool 
ObjectPool<Foo> Pool; 

//"using" ensures the reference is disposed at the end of the block, releasing the object back to the pool 
using (var Ref = Pool.GetObject()) 
{ 
    Ref.Instance.DoSomething(); 
}