ภาพรวม
Namespace System.Collections.Concurrent จัดเตรียมคอลเลกชันที่ Thread-Safe และ Scalable สำหรับ Multi-threaded Applications
คอลเลกชันหลัก
| Class | Type | Use Case | Key Methods |
|---|---|---|---|
ConcurrentDictionary<TKey,TValue> | Dictionary | Thread-safe key-value store, Cache | GetOrAdd, AddOrUpdate, TryGetValue, TryRemove |
ConcurrentQueue<T> | FIFO Queue | Producer-Consumer, Task Queue | Enqueue, TryDequeue, TryPeek |
ConcurrentStack<T> | LIFO Stack | Object Pooling, Undo Operations | Push, TryPop, TryPeek, PushRange, PopRange |
ConcurrentBag<T> | Unordered Bag | Thread-local Aggregation | Add, TryTake, TryPeek |
BlockingCollection<T> | Wrapper | Bounded Buffer, Producer-Consumer with Blocking | Add, Take, TryAdd, TryTake, CompleteAdding, GetConsumingEnumerable |
IProducerConsumerCollection<T> | Interface | Custom Concurrent Collections | TryAdd, TryTake, ToArray |
ตัวอย่าง: ConcurrentDictionary
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
public class Demo {
static ConcurrentDictionary<string, int> _counts = new ConcurrentDictionary<string, int>();
public static void Main() {
Parallel.For(0, 1000, i => {
string key = $"Key{i % 10}";
// Atomic Add/Update
_counts.AddOrUpdate(key, 1, (k, v) => v + 1);
});
foreach (var kvp in _counts.OrderBy(x => x.Key)) {
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}
}
}
ตัวอย่าง: ConcurrentStack
using System;
using System.Collections.Concurrent;
class Demo {
static void Main() {
var stack = new ConcurrentStack<int>();
stack.Push(50);
stack.Push(100);
stack.Push(150);
Console.WriteLine($"Is Empty: {stack.IsEmpty}"); // False
if (stack.TryPop(out int result)) {
Console.WriteLine($"Popped: {result}"); // 150
}
if (stack.TryPeek(out int peeked)) {
Console.WriteLine($"Peeked: {peeked}"); // 100
}
// Push/Pop Range (Efficient for batches)
int[] items = { 1, 2, 3, 4, 5 };
stack.PushRange(items);
int[] popped = new int[3];
int count = stack.TryPopRange(popped);
Console.WriteLine($"Popped {count} items: {string.Join(", ", popped.Take(count))}");
}
}
ตัวอย่าง: BlockingCollection (Producer-Consumer)
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
var queue = new BlockingCollection<int>(boundedCapacity: 5);
// Producer
Task.Run(() => {
for (int i = 0; i < 10; i++) {
queue.Add(i); // Blocks if full
Console.WriteLine($"Produced: {i}");
Thread.Sleep(100);
}
queue.CompleteAdding();
});
// Consumer
Task.Run(() => {
foreach (var item in queue.GetConsumingEnumerable()) {
Console.WriteLine($"Consumed: {item}");
Thread.Sleep(200);
}
}).Wait();
การเลือกใช้
- ConcurrentDictionary: Cache, Shared State, Lookup by Key
- ConcurrentQueue: FIFO Task Queue, Message Passing
- ConcurrentStack: LIFO, Object Pooling, Undo
- ConcurrentBag: Unordered, High Contention, Thread-local Aggregation
- BlockingCollection: Bounded Buffer, Backpressure, Producer-Consumer Pattern
Performance Notes
- ใช้ Lock-free / Fine-grained Locking / SpinWait
- หลีกเลี่ยงการ Lock เองบน Concurrent Collections
Try*Methods ไม่ Throw Exception คืน bool แทน