Created
October 27, 2025 13:39
-
-
Save sunmeat/5448b70f890dbc9326beae72e48d3d76 to your computer and use it in GitHub Desktop.
parallel collections C#
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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