Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
BlockingCollection<T> egy szálbiztos gyűjteményosztály, amely a következő funkciókat biztosítja:
A Producer-Consumer minta implementálása.
Több szál elemeinek egyidejű hozzáadása és felvétele.
Nem kötelező maximális kapacitás.
Olyan beszúrási és eltávolítási műveletek, amelyek letiltják, ha a gyűjtemény üres vagy megtelt.
Olyan beszúrási és eltávolítási "try" műveletek, amelyek nem blokkolnak, vagy csak egy meghatározott ideig blokkolnak.
Kapszuláz minden olyan gyűjteménytípust, amely megvalósít IProducerConsumerCollection<T>
Lemondás lemondási jogkivonatokkal.
Kétféle enumerálás a
foreach(For EachVisual Basicben):Írásvédett felsorolás.
Enumerálás, amely eltávolítja az elemeket az enumerálásuk közben.
Határolókeret és letiltás támogatása
BlockingCollection<T> támogatja a határolást és a blokkolást. A határolókeret azt jelenti, hogy beállíthatja a gyűjtemény maximális kapacitását. Bizonyos helyzetekben a határolókeretezés azért fontos, mert lehetővé teszi a gyűjtemény maximális méretének szabályozását a memóriában, és megakadályozza, hogy a termelő szálak túl messze haladjanak a fogyasztó szálak előtt.
Egyszerre több szál vagy tevékenység is hozzáadhat elemeket a gyűjteményhez, és ha a gyűjtemény eléri a megadott maximális kapacitást, a termelő szálak blokkolva lesznek, amíg el nem távolít egy elemet. Egyszerre több felhasználó is eltávolíthatja az elemeket, és ha a gyűjtemény üressé válik, a fogyasztó szálak blokkolva lesznek, amíg egy gyártó fel nem vesz egy elemet. Egy termelőszál meghívhatja CompleteAdding, hogy jelezze, hogy több elem nem lesz hozzáadva. A felhasználók figyelik a IsCompleted tulajdonságot, hogy megtudják, mikor üres a gyűjtemény, és nem lesz több elem hozzáadva. Az alábbi példa egy 100-ból álló korlátozott kapacitású, egyszerű BlockingCollection-et mutat be. A gyártói feladat addig ad hozzá elemeket a gyűjteményhez, amíg valamilyen külső feltétel teljesül, majd meghívja a CompleteAdding. A fogyasztói tevékenység addig veszi az elemeket, amíg a IsCompleted tulajdonság igaz.
// A bounded collection. It can hold no more
// than 100 items at once.
BlockingCollection<Data> dataItems = new BlockingCollection<Data>(100);
// A simple blocking consumer with no cancellation.
Task.Run(() =>
{
while (!dataItems.IsCompleted)
{
Data data = null;
// Blocks if dataItems.Count == 0.
// IOE means that Take() was called on a completed collection.
// Some other thread can call CompleteAdding after we pass the
// IsCompleted check but before we call Take.
// In this example, we can simply catch the exception since the
// loop will break on the next iteration.
try
{
data = dataItems.Take();
}
catch (InvalidOperationException) { }
if (data != null)
{
Process(data);
}
}
Console.WriteLine("\r\nNo more items to take.");
});
// A simple blocking producer with no cancellation.
Task.Run(() =>
{
while (moreItemsToAdd)
{
Data data = GetData();
// Blocks if numbers.Count == dataItems.BoundedCapacity
dataItems.Add(data);
}
// Let consumer know we are done.
dataItems.CompleteAdding();
});
' A bounded collection. It can hold no more
' than 100 items at once.
Dim dataItems = New BlockingCollection(Of Data)(100)
' A simple blocking consumer with no cancellation.
Task.Factory.StartNew(Sub()
While dataItems.IsCompleted = False
Dim dataItem As Data = Nothing
Try
dataItem = dataItems.Take()
Catch e As InvalidOperationException
' IOE means that Take() was called on a completed collection.
' In this example, we can simply catch the exception since the
' loop will break on the next iteration.
End Try
If (dataItem IsNot Nothing) Then
Process(dataItem)
End If
End While
Console.WriteLine(vbCrLf & "No more items to take.")
End Sub)
' A simple blocking producer with no cancellation.
Task.Factory.StartNew(Sub()
While moreItemsToAdd = True
Dim item As Data = GetData()
' Blocks if dataItems.Count = dataItems.BoundedCapacity.
dataItems.Add(item)
End While
' Let consumer know we are done.
dataItems.CompleteAdding()
End Sub)
Egy teljes példáért lásd: Elemek hozzáadása és felvétele egyenként a BlockingCollectionből.
Időzított blokkolási műveletek
A korlátozott gyűjtemények időzített blokkolása TryAdd és TryTake műveletei esetén a metódus megpróbál elemeket hozzáadni vagy felvenni. Ha egy elem elérhető, az a hivatkozás által átadott változóba kerül, és a metódus igaz értéket ad vissza. Ha a rendszer egy megadott időtúllépési időszak után nem kér le elemet, a metódus hamis értéket ad vissza. A szál ezután szabadon elvégezhet néhány más hasznos munkát, mielőtt újra megpróbálná elérni a gyűjteményt. Az időzítendő blokkolási hozzáférésről a második példát a How to: Add and Take Items Individually from a BlockingCollection (Elemek hozzáadása és felvétele önállóan a BlockingCollectionből) című témakörben talál.
Hozzáadás és átvétel műveletek megszakítása
A hozzáadási és a felvételi műveletek általában ciklusban hajthatók végre. Megszakíthat egy hurkot, ha egy CancellationToken paramétert ad át a TryAdd vagy TryTake metódusnak, majd az egyes iterációkban ellenőrzi a token IsCancellationRequested tulajdonságának értékét. Ha az érték igaz, akkor Önnek kell válaszolnia a lemondási kérelemre az erőforrások megtisztításával és a ciklusból való kilépéssel. Az alábbi példa egy túlterhelést mutat be, amely megszakítási TryAdd tokent használ, valamint az azt használó kódot.
do
{
// Cancellation causes OCE. We know how to handle it.
try
{
success = bc.TryAdd(itemToAdd, 2, ct);
}
catch (OperationCanceledException)
{
bc.CompleteAdding();
break;
}
//...
} while (moreItems == true);
Do While moreItems = True
' Cancellation causes OCE. We know how to handle it.
Try
success = bc.TryAdd(itemToAdd, 2, ct)
Catch ex As OperationCanceledException
bc.CompleteAdding()
Exit Do
End Try
Loop
A lemondási támogatás hozzáadásának módjáról a második példát a How to: Add and Take Items Individually from a BlockingCollection (Elemek hozzáadása és felvétele önállóan a BlockingCollectionből) című témakörben talál.
A gyűjtemény típusának megadása
Amikor létrehoz egy gyűjteményt BlockingCollection<T>, nemcsak a határolt kapacitást, hanem a használni kívánt gyűjtemény típusát is megadhatja. Megadhat például egy ConcurrentQueue<T> első be-első ki (FIFO) viselkedést, vagy egy ConcurrentStack<T> utolsó be-első ki (LIFO) viselkedést. Bármilyen olyan gyűjteményosztályt használhat, amely implementálja a IProducerConsumerCollection<T> felületet. Az alapértelmezett gyűjteménytípus a BlockingCollection<T> a ConcurrentQueue<T>. Az alábbi példakód bemutatja, hogyan hozhat létre stringekből álló BlockingCollection<T> 1000 kapacitással rendelkező ConcurrentBag<T> használatával.
Dim bc = New BlockingCollection(Of String)(New ConcurrentBag(Of String()), 1000)
BlockingCollection<string> bc = new BlockingCollection<string>(new ConcurrentBag<string>(), 1000 );
További információkért lásd: Határolókeret- és blokkolási funkciók hozzáadása gyűjteményhez.
IEnumerable-támogatás
BlockingCollection<T> Olyan GetConsumingEnumerable módszert biztosít, amellyel a felhasználók a gyűjtemény befejezéséig használhatják foreach (For Each a Visual Basicben) az elemek eltávolítását, ami azt jelenti, hogy üres, és nem lesz több elem hozzáadva. További információért lásd: ForEach használata a BlockingCollection elemeinek eltávolításához.
Több BlockingCollection felhasználása egyként
Olyan forgatókönyvek esetén, amikor a fogyasztónak egyszerre több gyűjteményből kell elemeket vennie, létrehozhat tömböket, és használhatja az olyan statikus metódusokat, mint például BlockingCollection<T>, TakeFromAny és AddToAny, amelyekkel a tömb bármely gyűjteményéhez hozzáadhat vagy azokból kivehet elemeket. Ha egy gyűjtemény blokkolva van, a metódus azonnal megpróbál egy másikat, amíg meg nem találja a műveletet végrehajtót. További információért lásd Hogyan: Blokkgyűjtemények tömbjeinek használata egy folyamatban.