Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Created October 27, 2025 13:39
Show Gist options
  • Save sunmeat/5448b70f890dbc9326beae72e48d3d76 to your computer and use it in GitHub Desktop.
Save sunmeat/5448b70f890dbc9326beae72e48d3d76 to your computer and use it in GitHub Desktop.
parallel collections C#
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
class Program
{
static void Main()
{
Console.OutputEncoding = Encoding.UTF8;
ConcurrentQueueDemo();
ConcurrentStackDemo();
ConcurrentBagDemo();
ConcurrentDictionaryDemo();
BlockingCollectionDemo();
ThreadLocalDemo();
}
static void ConcurrentQueueDemo()
{
// ConcurrentQueue<t> - потокобезпечна черга з безблокувальним алгоритмом, використовує 32 масиви в зв'язному списку
// методи enqueue, trydequeue, trypeek; реалізовує iproducerconsumercollection<t> з tryadd/trytake
var queue = new ConcurrentQueue<string>();
queue.Enqueue("Київ");
queue.Enqueue("Львів");
if (queue.TryDequeue(out string city))
Console.WriteLine("вилучено: " + city); // Київ
if (queue.TryPeek(out city))
Console.WriteLine("огляд: " + city); // Львів
Console.WriteLine("після вилучення: " + queue.Count); // 1
Console.WriteLine();
}
static void ConcurrentStackDemo()
{
// ConcurrentStack<t> - потокобезпечний стек з зв'язним списком, методи push/pushrange, trypeek/trypop/trypoprange
// підтримує масове додавання/вилучення для ефективності в багатопотоковому середовищі
var stack = new ConcurrentStack<string>();
stack.Push("Одеса");
stack.Push("Харків");
if (stack.TryPop(out string city))
Console.WriteLine("вилучено: " + city); // Харків
if (stack.TryPeek(out city))
Console.WriteLine("огляд: " + city); // Одеса
Console.WriteLine("після вилучення: " + stack.Count); // 1
Console.WriteLine();
}
static void ConcurrentBagDemo()
{
// ConcurrentBag<t> - потокобезпечний мішок без порядку, відображає потоки на внутрішні масиви для уникнення блокувань
// методи add, trypeek, trytake; ідеальний для сценаріїв, де порядок не важливий
// називається "мішком", оскільки елементи можуть бути вилучені в будь-якому порядку
var bag = new ConcurrentBag<string>();
bag.Add("Дніпро");
bag.Add("Запоріжжя");
if (bag.TryTake(out string city))
Console.WriteLine("вилучено: " + city); // один з елементів
if (bag.TryPeek(out city))
Console.WriteLine("огляд: " + city); // один з елементів
Console.WriteLine("після вилучення: " + bag.Count); // 1
Console.WriteLine();
}
static void ConcurrentDictionaryDemo()
{
// ConcurrentDictionary<tkey, tvalue> - потокобезпечний словник ключ-значень з неблокувальними tryadd, trygetvalue, tryremove, tryupdate
// не реалізовує iproducerconsumercollection<t>, фокус на атомарних операціях для ключів/значень
var dict = new ConcurrentDictionary<string, string>();
dict.TryAdd("столиця", "Київ");
dict.TryAdd("культурна", "Львів");
if (dict.TryGetValue("столиця", out string value))
Console.WriteLine("значення 'столиця': " + value);
dict.TryUpdate("столиця", "Київ (оновлено)", "Київ");
Console.WriteLine("оновлене значення 'столиця': " + dict["столиця"]);
Console.WriteLine("кількість: " + dict.Count);
Console.WriteLine();
}
static void BlockingCollectionDemo()
{
// BlockingCollection<t> - блокує потік до можливості додавання/вилучення, методи add/take з cancellationtoken
// tryadd/trytake з таймаутом для уникнення вічного блокування; обгортка над іншими concurrent колекціями
// особливість цього типу колекції - можливість блокування потоків при спробі додати або вилучити елементи
var bc = new BlockingCollection<string>(new ConcurrentQueue<string>());
var cts = new CancellationTokenSource();
Task producer = Task.Run(() =>
{
bc.Add("Київ", cts.Token);
bc.Add("Львів", cts.Token);
bc.CompleteAdding();
});
Task consumer = Task.Run(() =>
{
try
{
string city = bc.Take(cts.Token);
Console.WriteLine("взято: " + city); // Київ
if (bc.TryTake(out city, 1000)) // 1 сек таймаут
Console.WriteLine("взято з таймаутом: " + city); // Львів
}
catch (OperationCanceledException)
{
Console.WriteLine("операція скасована");
}
});
Task.WaitAll(producer, consumer);
Console.WriteLine("завершено: " + (bc.IsCompleted ? "так" : "ні"));
Console.WriteLine();
}
static void ThreadLocalDemo()
{
// ThreadLocal<t> - потокобезпечне локальне зберігання значень для кожного потоку, автоматично очищується при завершенні потоку
// методи value/isvaluecreated/values; корисне для thread-specific даних без блокувань
// потрібен для зберігання даних, специфічних для кожного потоку, без необхідності блокувань
var localCounter = new ThreadLocal<int>(() => 0, true); // trackallvalues=true
Parallel.For(0, Environment.ProcessorCount, i =>
{
localCounter.Value++;
Console.WriteLine($"потік {Thread.CurrentThread.ManagedThreadId}: локальний лічильник = {localCounter.Value}");
});
foreach (int count in localCounter.Values)
Console.WriteLine("значення з усіх потоків: " + count);
Console.WriteLine();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment