generic <typename T>
public ref class BlockingCollection : IDisposable, System::Collections::Generic::IEnumerable<T>, System::Collections::Generic::IReadOnlyCollection<T>, System::Collections::ICollection
generic <typename T>
public ref class BlockingCollection : IDisposable, System::Collections::Generic::IEnumerable<T>, System::Collections::ICollection
public class BlockingCollection<T> : IDisposable, System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.ICollection
[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
public class BlockingCollection<T> : IDisposable, System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.ICollection
[System.Runtime.InteropServices.ComVisible(false)]
public class BlockingCollection<T> : IDisposable, System.Collections.Generic.IEnumerable<T>, System.Collections.ICollection
[System.Runtime.InteropServices.ComVisible(false)]
public class BlockingCollection<T> : IDisposable, System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.ICollection
public class BlockingCollection<T> : IDisposable, System.Collections.Generic.IEnumerable<T>, System.Collections.ICollection
type BlockingCollection<'T> = class
interface seq<'T>
interface IEnumerable
interface IReadOnlyCollection<'T>
interface ICollection
interface IDisposable
[<System.Runtime.Versioning.UnsupportedOSPlatform("browser")>]
type BlockingCollection<'T> = class
interface seq<'T>
interface IEnumerable
interface IReadOnlyCollection<'T>
interface ICollection
interface IDisposable
[<System.Runtime.InteropServices.ComVisible(false)>]
type BlockingCollection<'T> = class
interface seq<'T>
interface ICollection
interface IEnumerable
interface IDisposable
[<System.Runtime.InteropServices.ComVisible(false)>]
type BlockingCollection<'T> = class
interface seq<'T>
interface IEnumerable
interface ICollection
interface IDisposable
interface IReadOnlyCollection<'T>
type BlockingCollection<'T> = class
interface seq<'T>
interface ICollection
interface IEnumerable
interface IDisposable
Public Class BlockingCollection(Of T)
Implements ICollection, IDisposable, IEnumerable(Of T), IReadOnlyCollection(Of T)
Public Class BlockingCollection(Of T)
Implements ICollection, IDisposable, IEnumerable(Of T)
await AddTakeDemo.BC_AddTakeCompleteAdding();
TryTakeDemo.BC_TryTake();
FromToAnyDemo.BC_FromToAny();
await ConsumingEnumerableDemo.BC_GetConsumingEnumerable();
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
class AddTakeDemo
// Demonstrates:
// BlockingCollection<T>.Add()
// BlockingCollection<T>.Take()
// BlockingCollection<T>.CompleteAdding()
public static async Task BC_AddTakeCompleteAdding()
using (BlockingCollection<int> bc = new BlockingCollection<int>())
// Spin up a Task to populate the BlockingCollection
Task t1 = Task.Run(() =>
bc.Add(1);
bc.Add(2);
bc.Add(3);
bc.CompleteAdding();
// Spin up a Task to consume the BlockingCollection
Task t2 = Task.Run(() =>
// Consume the BlockingCollection
while (true) Console.WriteLine(bc.Take());
catch (InvalidOperationException)
// An InvalidOperationException means that Take() was called on a completed collection
Console.WriteLine("That's All!");
await Task.WhenAll(t1, t2);
class TryTakeDemo
// Demonstrates:
// BlockingCollection<T>.Add()
// BlockingCollection<T>.CompleteAdding()
// BlockingCollection<T>.TryTake()
// BlockingCollection<T>.IsCompleted
public static void BC_TryTake()
// Construct and fill our BlockingCollection
using (BlockingCollection<int> bc = new BlockingCollection<int>())
int NUMITEMS = 10000;
for (int i = 0; i < NUMITEMS; i++) bc.Add(i);
bc.CompleteAdding();
int outerSum = 0;
// Delegate for consuming the BlockingCollection and adding up all items
Action action = () =>
int localItem;
int localSum = 0;
while (bc.TryTake(out localItem)) localSum += localItem;
Interlocked.Add(ref outerSum, localSum);
// Launch three parallel actions to consume the BlockingCollection
Parallel.Invoke(action, action, action);
Console.WriteLine("Sum[0..{0}) = {1}, should be {2}", NUMITEMS, outerSum, ((NUMITEMS * (NUMITEMS - 1)) / 2));
Console.WriteLine("bc.IsCompleted = {0} (should be true)", bc.IsCompleted);
class FromToAnyDemo
// Demonstrates:
// Bounded BlockingCollection<T>
// BlockingCollection<T>.TryAddToAny()
// BlockingCollection<T>.TryTakeFromAny()
public static void BC_FromToAny()
BlockingCollection<int>[] bcs = new BlockingCollection<int>[2];
bcs[0] = new BlockingCollection<int>(5); // collection bounded to 5 items
bcs[1] = new BlockingCollection<int>(5); // collection bounded to 5 items
// Should be able to add 10 items w/o blocking
int numFailures = 0;
for (int i = 0; i < 10; i++)
if (BlockingCollection<int>.TryAddToAny(bcs, i) == -1) numFailures++;
Console.WriteLine("TryAddToAny: {0} failures (should be 0)", numFailures);
// Should be able to retrieve 10 items
int numItems = 0;
int item;
while (BlockingCollection<int>.TryTakeFromAny(bcs, out item) != -1) numItems++;
Console.WriteLine("TryTakeFromAny: retrieved {0} items (should be 10)", numItems);
class ConsumingEnumerableDemo
// Demonstrates:
// BlockingCollection<T>.Add()
// BlockingCollection<T>.CompleteAdding()
// BlockingCollection<T>.GetConsumingEnumerable()
public static async Task BC_GetConsumingEnumerable()
using (BlockingCollection<int> bc = new BlockingCollection<int>())
// Kick off a producer task
var producerTask = Task.Run(async () =>
for (int i = 0; i < 10; i++)
bc.Add(i);
Console.WriteLine($"Producing: {i}");
await Task.Delay(100); // sleep 100 ms between adds
// Need to do this to keep foreach below from hanging
bc.CompleteAdding();
// Now consume the blocking collection with foreach.
// Use bc.GetConsumingEnumerable() instead of just bc because the
// former will block waiting for completion and the latter will
// simply take a snapshot of the current state of the underlying collection.
foreach (var item in bc.GetConsumingEnumerable())
Console.WriteLine($"Consuming: {item}");
await producerTask; // Allow task to complete cleanup
open System
open System.Collections.Concurrent
open System.Threading
open System.Threading.Tasks
module AddTakeDemo =
// Demonstrates:
// BlockingCollection<T>.Add()
// BlockingCollection<T>.Take()
// BlockingCollection<T>.CompleteAdding()
let blockingCollectionAddTakeCompleteAdding () =
task {
use bc = new BlockingCollection<int>()
// Spin up a Task to populate the BlockingCollection
let t1 =
task {
bc.Add 1
bc.Add 2
bc.Add 3
bc.CompleteAdding()
// Spin up a Task to consume the BlockingCollection
let t2 =
task {
// Consume consume the BlockingCollection
while true do
printfn $"{bc.Take()}"
with :? InvalidOperationException ->
// An InvalidOperationException means that Take() was called on a completed collection
printfn "That's All!"
let! _ = Task.WhenAll(t1, t2)
module TryTakeDemo =
// Demonstrates:
// BlockingCollection<T>.Add()
// BlockingCollection<T>.CompleteAdding()
// BlockingCollection<T>.TryTake()
// BlockingCollection<T>.IsCompleted
let blockingCollectionTryTake () =
// Construct and fill our BlockingCollection
use bc = new BlockingCollection<int>()
let NUMITEMS = 10000;
for i = 0 to NUMITEMS - 1 do
bc.Add i
bc.CompleteAdding()
let mutable outerSum = 0
// Delegate for consuming the BlockingCollection and adding up all items
let action =
Action(fun () ->
let mutable localItem = 0
let mutable localSum = 0
while bc.TryTake &localItem do
localSum <- localSum + localItem
Interlocked.Add(&outerSum, localSum)
|> ignore)
// Launch three parallel actions to consume the BlockingCollection
Parallel.Invoke(action, action, action)
printfn $"Sum[0..{NUMITEMS}) = {outerSum}, should be {((NUMITEMS * (NUMITEMS - 1)) / 2)}"
printfn $"bc.IsCompleted = {bc.IsCompleted} (should be true)"
module FromToAnyDemo =
// Demonstrates:
// Bounded BlockingCollection<T>
// BlockingCollection<T>.TryAddToAny()
// BlockingCollection<T>.TryTakeFromAny()
let blockingCollectionFromToAny () =
let bcs =
new BlockingCollection<int>(5) // collection bounded to 5 items
new BlockingCollection<int>(5) // collection bounded to 5 items
// Should be able to add 10 items w/o blocking
let mutable numFailures = 0;
for i = 0 to 9 do
if BlockingCollection<int>.TryAddToAny(bcs, i) = -1 then
numFailures <- numFailures + 1
printfn $"TryAddToAny: {numFailures} failures (should be 0)"
// Should be able to retrieve 10 items
let mutable numItems = 0
let mutable item = 0
while BlockingCollection<int>.TryTakeFromAny(bcs, &item) <> -1 do
numItems <- numItems + 1
printfn $"TryTakeFromAny: retrieved {numItems} items (should be 10)"
module ConsumingEnumerableDemo =
// Demonstrates:
// BlockingCollection<T>.Add()
// BlockingCollection<T>.CompleteAdding()
// BlockingCollection<T>.GetConsumingEnumerable()
let blockingCollectionGetConsumingEnumerable () =
task {
use bc = new BlockingCollection<int>()
// Kick off a producer task
let producerTask =
task {
for i = 0 to 9 do
bc.Add i
printfn $"Producing: {i}"
do! Task.Delay 100 // sleep 100 ms between adds
// Need to do this to keep foreach below from hanging
bc.CompleteAdding()
// Now consume the blocking collection with foreach.
// Use bc.GetConsumingEnumerable() instead of just bc because the
// former will block waiting for completion and the latter will
// simply take a snapshot of the current state of the underlying collection.
for item in bc.GetConsumingEnumerable() do
printfn $"Consuming: {item}"
do! producerTask // Allow task to complete cleanup
let main =
task {
do! AddTakeDemo.blockingCollectionAddTakeCompleteAdding ()
TryTakeDemo.blockingCollectionTryTake ()
FromToAnyDemo.blockingCollectionFromToAny ()
do! ConsumingEnumerableDemo.blockingCollectionGetConsumingEnumerable ()
printfn "Press any key to exit."
Console.ReadKey(true) |> ignore
main.Wait()
Imports System.Threading.Tasks
Imports System.Collections.Concurrent
Imports System.Threading
Class BlockingCollectionDemo
Shared Sub Main()
AddTakeDemo.BC_AddTakeCompleteAdding()
TryTakeDemo.BC_TryTake()
ToAnyDemo.BC_ToAny()
ConsumingEnumerableDemo.BC_GetConsumingEnumerable()
' Keep the console window open in debug mode
Console.WriteLine("Press any key to exit.")
Console.ReadKey()
End Sub
End Class
Class AddTakeDemo
' Demonstrates:
' BlockingCollection<T>.Add()
' BlockingCollection<T>.Take()
' BlockingCollection<T>.CompleteAdding()
Shared Sub BC_AddTakeCompleteAdding()
Using bc As New BlockingCollection(Of Integer)()
' Spin up a Task to populate the BlockingCollection
Using t1 As Task = Task.Factory.StartNew(
Sub()
bc.Add(1)
bc.Add(2)
bc.Add(3)
bc.CompleteAdding()
End Sub)
' Spin up a Task to consume the BlockingCollection
Using t2 As Task = Task.Factory.StartNew(
Sub()
' Consume the BlockingCollection
While True
Console.WriteLine(bc.Take())
End While
Catch generatedExceptionName As InvalidOperationException
' An InvalidOperationException means that Take() was called on a completed collection
Console.WriteLine("That's All!")
End Try
End Sub)
Task.WaitAll(t1, t2)
End Using
End Using
End Using
End Sub
End Class
'Imports System.Collections.Concurrent
'Imports System.Threading
'Imports System.Threading.Tasks
Class TryTakeDemo
' Demonstrates:
' BlockingCollection<T>.Add()
' BlockingCollection<T>.CompleteAdding()
' BlockingCollection<T>.TryTake()
' BlockingCollection<T>.IsCompleted
Shared Sub BC_TryTake()
' Construct and fill our BlockingCollection
Using bc As New BlockingCollection(Of Integer)()
Dim NUMITEMS As Integer = 10000
For i As Integer = 0 To NUMITEMS - 1
bc.Add(i)
bc.CompleteAdding()
Dim outerSum As Integer = 0
' Delegate for consuming the BlockingCollection and adding up all items
Dim action As Action =
Sub()
Dim localItem As Integer
Dim localSum As Integer = 0
While bc.TryTake(localItem)
localSum += localItem
End While
Interlocked.Add(outerSum, localSum)
End Sub
' Launch three parallel actions to consume the BlockingCollection
Parallel.Invoke(action, action, action)
Console.WriteLine("Sum[0..{0}) = {1}, should be {2}", NUMITEMS, outerSum, ((NUMITEMS * (NUMITEMS - 1)) / 2))
Console.WriteLine("bc.IsCompleted = {0} (should be true)", bc.IsCompleted)
End Using
End Sub
End Class
'Imports System.Threading.Tasks
'Imports System.Collections.Concurrent
' Demonstrates:
' Bounded BlockingCollection<T>
' BlockingCollection<T>.TryAddToAny()
' BlockingCollection<T>.TryTakeFromAny()
Class ToAnyDemo
Shared Sub BC_ToAny()
Dim bcs As BlockingCollection(Of Integer)() = New BlockingCollection(Of Integer)(1) {}
bcs(0) = New BlockingCollection(Of Integer)(5)
' collection bounded to 5 items
bcs(1) = New BlockingCollection(Of Integer)(5)
' collection bounded to 5 items
' Should be able to add 10 items w/o blocking
Dim numFailures As Integer = 0
For i As Integer = 0 To 9
If BlockingCollection(Of Integer).TryAddToAny(bcs, i) = -1 Then
numFailures += 1
End If
Console.WriteLine("TryAddToAny: {0} failures (should be 0)", numFailures)
' Should be able to retrieve 10 items
Dim numItems As Integer = 0
Dim item As Integer
While BlockingCollection(Of Integer).TryTakeFromAny(bcs, item) <> -1
numItems += 1
End While
Console.WriteLine("TryTakeFromAny: retrieved {0} items (should be 10)", numItems)
End Sub
End Class
'Imports System.Threading.Tasks
'Imports System.Collections.Concurrent
' Demonstrates:
' BlockingCollection<T>.Add()
' BlockingCollection<T>.CompleteAdding()
' BlockingCollection<T>.GetConsumingEnumerable()
Class ConsumingEnumerableDemo
Shared Sub BC_GetConsumingEnumerable()
Using bc As New BlockingCollection(Of Integer)()
' Kick off a producer task
Task.Factory.StartNew(
Sub()
For i As Integer = 0 To 9
bc.Add(i)
' sleep 100 ms between adds
Thread.Sleep(100)
' Need to do this to keep foreach below from not responding.
bc.CompleteAdding()
End Sub)
' Now consume the blocking collection with foreach.
' Use bc.GetConsumingEnumerable() instead of just bc because the
' former will block waiting for completion and the latter will
' simply take a snapshot of the current state of the underlying collection.
For Each item In bc.GetConsumingEnumerable()
Console.WriteLine(item)
End Using
End Sub
End Class
BlockingCollection<T>
是安全線程集合類別,提供下列專案:
產生者/取用者模式的實作;
BlockingCollection<T>
是介面的
IProducerConsumerCollection<T>
包裝函式。
使用
Add
和
Take
方法,同時從多個線程新增和移除專案。
當集合已滿或空白時,會封鎖
Add
和
Take
作業的界限集合。
Add
在或
TryTake
方法中使用
TryAdd
CancellationToken
物件取消 或
Take
作業。
此型別代表
IDisposable
介面。 當您完成使用型別時,您應該直接或間接處置它。 若要直接處置型別,請呼叫其
try
/
catch
區塊中的
Dispose
方法。 若要間接處置它,請使用語言建構函式,例如
using
(在 C# 中) 或
Using
(在 Visual Basic 中)。 如需詳細資訊,請參閱
IDisposable
介面文章中的<使用實作 IDisposable 的物件>一節。 此外,請注意,方法
Dispose()
不是安全線程。 的所有其他公用和受保護成員
BlockingCollection<T>
都是安全線程,而且可以從多個線程同時使用。
IProducerConsumerCollection<T>
表示允許安全線程新增和移除數據的集合。
BlockingCollection<T>
會作為實例的
IProducerConsumerCollection<T>
包裝函式使用,並允許移除集合中的嘗試封鎖,直到數據可供移除為止。 同樣地,您可以建立 ,
BlockingCollection<T>
在 允許的數據元素
IProducerConsumerCollection<T>
數目上強制執行上限;接著,加入集合的嘗試可能會封鎖,直到空間可供儲存新增的項目為止。 如此一來,
BlockingCollection<T>
類似於傳統的封鎖佇列數據結構,不同之處在於基礎數據儲存機制會抽象化為
IProducerConsumerCollection<T>
。
BlockingCollection<T>
支援界限和封鎖。 周框表示您可以設定集合的最大容量。 在某些案例中,周框很重要,因為它可讓您控制記憶體中集合的大小上限,並防止產生線程在取用線程之前移動太遠。多個線程或工作可以同時將專案新增至集合,如果集合達到其指定的最大容量,則產生線程將會封鎖,直到移除項目為止。 多位消費者可以同時移除項目,如果集合變成空的,則會在生產者新增項目之前封鎖使用執行緒。 產生線程可以呼叫
CompleteAdding
方法,以指出不會再新增任何專案。 消費者會監視
IsCompleted
屬性,以得知集合何時變成空的,以及何時無法再新增項目。
Add
和
Take
作業通常會在迴圈中執行。 您可以藉由將
CancellationToken
對象傳入 或
TryTake
方法,然後在每次反覆項目上檢查令牌
IsCancellationRequested
屬性的值,
TryAdd
以取消迴圈。 如果值為
true
,則您可以清除任何資源並結束迴圈,以回應取消要求。
當您建立
BlockingCollection<T>
物件時,不僅可以指定限定的容量,也可以指定要使用的集合類型。 例如,您可以針對先進先出 (FIFO) 行為指定
ConcurrentQueue<T>
物件,或針對後進先出 (LIFO) 行為指定
ConcurrentStack<T>
物件。 您可以使用任何可實作
IProducerConsumerCollection<T>
介面的集合類別。
BlockingCollection<T>
的預設集合類型為
ConcurrentQueue<T>
。
請勿直接修改基礎集合。 使用
BlockingCollection<T>
方法來加入或移除專案。 如果您直接變更基礎集合,物件
BlockingCollection<T>
可能會損毀。
BlockingCollection<T>
未設計為以異步存取為考慮。 如果您的應用程式需要異步產生者/取用者案例,請考慮改用
Channel<T>
。
ToImmutableDictionary<TSource,TKey,TValue>(IEnumerable<TSource>,
Func<TSource,TKey>, Func<TSource,TValue>, IEqualityComparer<TKey>,
IEqualityComparer<TValue>)
列舉及轉換序列,並使用指定的索引鍵與值比較子產生其內容的不可變字典。
AggregateBy<TSource,TKey,TAccumulate>(IEnumerable<TSource>, Func<TSource,
TKey>, Func<TKey,TAccumulate>, Func<TAccumulate,TSource,TAccumulate>,
IEqualityComparer<TKey>)
提供安全執行緒集合適用的封鎖和界限容量,這個集合會實作
IProducerConsumerCollection<T>
。
GroupBy<TSource,TKey,TElement,TResult>(IEnumerable<TSource>, Func<TSource,
TKey>, Func<TSource,TElement>, Func<TKey,IEnumerable<TElement>,
TResult>, IEqualityComparer<TKey>)
依據指定的索引鍵選取器函式來群組序列的項目,並從每個群組及其索引鍵建立結果值。 索引鍵值是使用指定的比較子來進行比較,而每個群組的項目則都是利用指定的函式進行投影。
GroupJoin<TOuter,TInner,TKey,TResult>(IEnumerable<TOuter>, IEnumerable<TInner>,
Func<TOuter,TKey>, Func<TInner,TKey>, Func<TOuter,IEnumerable<TInner>,
TResult>)
根據索引鍵相等與否,將兩個序列的項目相互關聯,並群組產生的結果。 預設的相等比較子是用於比較索引鍵。
GroupJoin<TOuter,TInner,TKey,TResult>(IEnumerable<TOuter>, IEnumerable<TInner>,
Func<TOuter,TKey>, Func<TInner,TKey>, Func<TOuter,IEnumerable<TInner>,
TResult>, IEqualityComparer<TKey>)
根據索引鍵相等與否,將兩個序列的項目相互關聯,並群組產生的結果。 指定的
IEqualityComparer<T>
是用於比較索引鍵。
Join<TOuter,TInner,TKey,TResult>(IEnumerable<TOuter>, IEnumerable<TInner>,
Func<TOuter,TKey>, Func<TInner,TKey>, Func<TOuter,TInner,TResult>,
IEqualityComparer<TKey>)
根據相符索引鍵,將兩個序列的項目相互關聯。 指定的
IEqualityComparer<T>
是用於比較索引鍵。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:
https://aka.ms/ContentUserFeedback
。
提交並檢視相關的意見反應