方法: ConcurrentBag を使用してオブジェクト プールを作成する
この例では、同時実行バッグを使用してオブジェクト プールを実装する方法を示します。 オブジェクト プールを実装すると、クラスの複数のインスタンスが必要で、クラスの作成時または破棄時の負荷が高い場合に、アプリケーションのパフォーマンスを向上できます。 クライアント プログラムによって新しいオブジェクトが要求されると、オブジェクト プールはまず、既に作成されてプールに返されているオブジェクトを提供しようとします。 オブジェクトが存在しない場合にのみ、新しいオブジェクトが作成されます。
ConcurrentBag<T> は高速な挿入と削除をサポートするので、オブジェクトの格納に使用されます。特に、同じスレッドが項目の追加と削除の両方を行っている場合に役立ちます。 この例は、ConcurrentQueue<T> および ConcurrentStack<T> と同様に、バッグ データ構造によって実装される IProducerConsumerCollection<T> を中心に構築してさらに強化することができます。
使用例
Imports System
Imports System.Collections.Concurrent
Imports System.Threading
Imports System.Threading.Tasks
Module ObjectPoolExample
Public Class ObjectPool(Of T)
Private _objects As ConcurrentBag(Of T)
Private _objectGenerator As Func(Of T)
Public Sub New(ByVal objectGenerator As Func(Of T))
If objectGenerator Is Nothing Then Throw New ArgumentNullException("objectGenerator")
_objects = New ConcurrentBag(Of T)()
_objectGenerator = objectGenerator
End Sub
Public Function GetObject() As T
Dim item As T
If _objects.TryTake(item) Then Return item
Return _objectGenerator()
End Function
Public Sub PutObject(ByVal item As T)
_objects.Add(item)
End Sub
End Class
Sub Main()
Dim cts As CancellationTokenSource = New CancellationTokenSource()
' Create an opportunity for the user to cancel.
Task.Factory.StartNew(Sub()
If Console.ReadKey().KeyChar = "c"c Or Console.ReadKey().KeyChar = "C"c Then
cts.Cancel()
End If
End Sub)
Dim pool As ObjectPool(Of TestClass) = New ObjectPool(Of TestClass)(Function() New TestClass())
' Create a high demand for TestClass objects.
Parallel.For(0, 1000000, Sub(i, loopState)
Dim mc As TestClass = pool.GetObject()
Console.CursorLeft = 0
' This is the bottleneck in our application. All threads in this loop
' must serialize their access to the static Console class.
Console.WriteLine("{0:####.####}", mc.GetValue(i))
pool.PutObject(mc)
If cts.Token.IsCancellationRequested Then
loopState.Stop()
End If
End Sub)
Console.WriteLine("Press the Enter key to exit.")
Console.ReadLine()
End Sub
' A toy class that requires some resources to create.
' You can experiment here to measure the performance of the
' object pool vs. ordinary instantiation.
Class TestClass
Public Nums() As Integer
Public Function GetValue(ByVal i As Long) As Double
Return Math.Sqrt(Nums(i))
End Function
Public Sub New()
Nums = New Integer(10000000) {}
' ReDim Nums(1000000)
Dim rand As Random = New Random()
For i As Integer = 0 To Nums.Length - 1
Nums(i) = rand.Next()
Next
End Sub
End Class
End Module
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace ObjectPoolExample
{
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);
}
}
class Program
{
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
// Create an opportunity for the user to cancel.
Task.Factory.StartNew(() =>
{
if (Console.ReadKey().KeyChar == 'c' || Console.ReadKey().KeyChar == 'C')
cts.Cancel();
});
ObjectPool<MyClass> pool = new ObjectPool<MyClass> (() => new MyClass());
// Create a high demand for MyClass objects.
Parallel.For(0, 1000000, (i, loopState) =>
{
MyClass mc = pool.GetObject();
Console.CursorLeft = 0;
// This is the bottleneck in our application. All threads in this loop
// must serialize their access to the static Console class.
Console.WriteLine("{0:####.####}", mc.GetValue(i));
pool.PutObject(mc);
if (cts.Token.IsCancellationRequested)
loopState.Stop();
});
Console.WriteLine("Press the Enter key to exit.");
Console.ReadLine();
}
}
// A toy class that requires some resources to create.
// You can experiment here to measure the performance of the
// object pool vs. ordinary instantiation.
class MyClass
{
public int[] Nums {get; set;}
public double GetValue(long i)
{
return Math.Sqrt(Nums[i]);
}
public MyClass()
{
Nums = new int[1000000];
Random rand = new Random();
for (int i = 0; i < Nums.Length; i++)
Nums[i] = rand.Next();
}
}
}