Українська
Завдання
Відповідно до номера свого варіанта виконайте завдання обраного рівня складності.
Варіанти
Варіант 1. Обробка вебжурналів
1. Початковий рівень. Створити консольну програму, яка генерує 10 000 рядків журналу вебсервера у форматі метод шлях код час_мс (фіксоване зерно генератора), передає їх з потоку-читача через обмежений канал Channel.CreateBounded<string>(100) двом розбирачам і виводить кількість відповідей для кожного коду стану (200, 404, 500 тощо).
2. Базовий рівень. Створити консольну програму, яка запитує шлях до текстового файлу журналу вебсервера (рядки метод шлях код час_мс), ємність каналу (1–10 000) і кількість розбирачів (1–16), перевіряє введення та обробляє файл конвеєром «читання → розбір → агрегація» на каналах. Програма виводить таблицю «код – кількість – частка, %», середній час відповіді, кількість пошкоджених рядків і час обробки; результат має збігатися з послідовним підрахунком, який програма виконує для перевірки.
3. Високий рівень. Створити консольний застосунок logstat, який приймає один або кілька файлів журналу та опції --parsers N, --capacity N, --top N, --out файл.csv і --help. Конвеєр на обмежених каналах читає файли, розбирає рядки в кількох задачах і агрегує статистику кодів стану та N найповільніших шляхів за середнім часом. Програма вимірює найбільшу кількість елементів у кожному каналі (прояв зворотного тиску), виводить вирівняні таблиці й записує їх у CSV. Відсутні файли та некоректні опції повідомляються в потік помилок; код завершення 0 – успіх, 1 – помилка аргументів, 2 – жоден файл не прочитано.
Варіант 2. Мініатюри фотографій (імітація)
1. Початковий рівень. Створити консольну програму, у якій потік-виробник додає 50 «фотографій» (назва й розмір у мегапікселях) в BlockingCollection<Photo> ємністю 10, а три обробники створюють «мініатюри», імітуючи роботу Thread.Sleep тривалістю 10 мс на мегапіксель. Програма виводить, який обробник обробив кожну фотографію, і загальну кількість оброблених.
2. Базовий рівень. Створити консольну програму, яка запитує кількість фотографій (1–1 000), ємність черги та кількість обробників (1–16), генерує фотографії випадкових розмірів (зерно 1) і обробляє їх за схемою «виробник – споживач» з імітацією роботи. Програма виводить таблицю «обробник – фотографій – сумарно мегапікселів», час роботи та пропускну здатність (фотографій за секунду) і перевіряє, що кожну фотографію оброблено рівно один раз.
3. Високий рівень. Створити консольний застосунок, який читає з CSV-файлу перелік фотографій (назва;ширина;висота) і приймає опції --capacity, --workers 1,2,4,8, --repeat та --help. Для кожної кількості обробників програма обробляє перелік через обмежену BlockingCollection<T> з імітацією роботи, пропорційною кількості пікселів, і виводить таблицю «обробників – час, мс – фото/с – прискорення – ефективність» (медіана повторів). Рядки з помилками формату пропускаються з повідомленням у потік помилок із номером рядка; порожній або відсутній файл дає код завершення 2.
Варіант 3. Телеметрія датчиків
1. Початковий рівень. Створити консольну програму, у якій потік-датчик за 1 с генерує події температури без затримки, записуючи їх методом TryWrite в канал ємністю 10 000 з режимом BoundedChannelFullMode.DropOldest, а повільний споживач обробляє кожну подію 0,1 мс. Програма виводить кількість створених, оброблених і втрачених подій (втрати рахувати делегатом itemDropped).
2. Базовий рівень. Створити консольну програму, яка запитує кількість датчиків (1–16), ємність каналу та режим переповнення (Wait, DropOldest, DropNewest, DropWrite), перевіряє введення та моделює 5 с роботи: датчики записують події в спільний обмежений канал, два споживачі обчислюють середню температуру кожного датчика. Програма виводить таблицю «датчик – створено – оброблено – середня температура» та частку втрачених подій.
3. Високий рівень. Створити консольний застосунок для порівняння режимів переповнення каналу з опціями --sensors, --rate подій/с, --capacity, --duration с, --consumer-delay мс, --csv файл і --help. Програма послідовно виконує моделювання для всіх чотирьох режимів BoundedChannelFullMode і виводить таблицю «режим – створено – оброблено – втрачено, % – найбільша затримка події, мс – середня затримка, мс». Затримку обчислювати за міткою часу події; результати дописуються у CSV-файл. Некоректні опції повідомляються в потік помилок з кодом завершення 1.
Варіант 4. Частотний словник творів
1. Початковий рівень. Створити консольну програму, яка читає текстовий файл, заданий у коді, ділить рядки на чотири частини та в чотирьох потоках рахує частоту слів у спільному ConcurrentDictionary<string, int> методом AddOrUpdate. Програма виводить 10 найчастіших слів і перевіряє результат порівнянням з послідовним підрахунком.
2. Базовий рівень. Створити консольну програму, яка запитує шлях до текстового файлу та кількість потоків (1–32) і будує частотний словник двома способами: спільний ConcurrentDictionary<string, int> та локальні Dictionary<string, int> у кожному потоці зі злиттям після завершення. Слова приводяться до нижнього регістру, розділові знаки відкидаються. Програма виводить час обох способів, ознаку збігу результатів і 15 найчастіших слів.
3. Високий рівень. Створити консольний застосунок, який приймає теку з текстовими файлами творів та опції --threads 1,2,4,8,16, --min-length, --top і --help. Для кожної кількості потоків програма будує частотний словник спільним ConcurrentDictionary<TKey, TValue> і локальними словниками зі злиттям, вимірює медіану трьох запусків після прогрівання та виводить таблицю «потоків – спільний словник, мс – локальні словники, мс – прискорення кожного способу». Окремо виводиться таблиця найчастіших слів з кількістю файлів, у яких вони трапляються. Порожня або відсутня тека – повідомлення в потік помилок і код завершення 2.
Варіант 5. Ресторанні замовлення
1. Початковий рівень. Створити консольну програму, у якій два офіціанти-виробники додають по 10 замовлень у спільну BlockingCollection<Order>, а три кухарі-споживачі готують їх (імітація 50 мс). Після завершення обох офіціантів викликати CompleteAdding. Програма виводить журнал «кухар – замовлення» і кількість замовлень кожного кухаря.
2. Базовий рівень. Створити консольну програму з двома чергами замовлень – терміновою та звичайною (BlockingCollection<Order>), яка запитує кількість офіціантів, кухарів і замовлень. Кухарі беруть замовлення методом BlockingCollection<Order>.TakeFromAny, перевіряючи спершу термінову чергу, і завершуються після закриття обох черг. Програма виводить таблицю «кухар – термінових – звичайних» і середній час очікування термінових та звичайних замовлень.
3. Високий рівень. Створити консольний застосунок, який читає з CSV-файлу сценарій замовлень (час_надходження_мс;стіл;страва;пріоритет) і моделює кухню з опціями --cooks N, --capacity N, --priorities 3 і --help. Кожна страва має час приготування з довідника, заданого у програмі. Застосунок коректно завершує всіх кухарів після останнього замовлення, виводить таблицю «пріоритет – замовлень – середнє очікування, мс – найбільше очікування, мс» та завантаженість кожного кухаря у відсотках. Невідомі страви та некоректні рядки записуються в потік помилок; якщо жодне замовлення не прийнято, код завершення 2.
Варіант 6. Вебкраулер (імітація графа сторінок)
1. Початковий рівень. Створити консольну програму, яка задає в коді граф із 20 «сторінок» (словник «адреса – посилання») і обходить його чотирма потоками, беручи адреси з ConcurrentQueue<string>. Відвідані адреси зберігаються в ConcurrentDictionary<string, byte> (метод TryAdd), щоб кожну сторінку обробити один раз. Програма виводить порядок обходу й кількість відвіданих сторінок.
2. Базовий рівень. Створити консольну програму, яка генерує випадковий граф сторінок (кількість сторінок і середня кількість посилань вводяться з клавіатури, зерно 7), запитує максимальну глибину та кількість потоків і обходить граф від стартової сторінки з імітацією завантаження 5 мс. Знайдені сторінки складаються в ConcurrentBag<string>. Програма виводить кількість сторінок на кожній глибині та перевіряє, що результат збігається з послідовним обходом у ширину.
3. Високий рівень. Створити консольний застосунок, який читає граф сторінок з файлу (рядки адреса -> посилання1 посилання2 …) і приймає опції --start, --depth, --workers, --max-pages, --delay мс та --help. Обхід виконується пулом обробників над каналом адрес; обробники завершуються, коли черга порожня й жоден з них не обробляє сторінку. Програма виводить таблицю «глибина – сторінок», перелік недосяжних сторінок, «биті» посилання на відсутні адреси та час обходу для заданої кількості обробників. Помилки формату файлу повідомляються з номером рядка в потік помилок.
Варіант 7. Фондова біржа
1. Початковий рівень. Створити консольну програму, у якій три потоки-трейдери записують по 20 заявок (купівля або продаж, ціна, кількість) у канал Channel<Order>, а один потік біржі читає заявки й рахує загальну кількість заявок на купівлю та продаж і середню ціну кожного типу.
2. Базовий рівень. Створити консольну програму, яка запитує кількість трейдерів і заявок кожного, генерує заявки на одну акцію (зерно 3) і передає їх через обмежений канал єдиному споживачу-біржі. Біржа зіставляє заявки: купівля виконується, якщо її ціна не менша за найнижчу ціну продажу. Програма виводить журнал угод «покупець – продавець – ціна – кількість», кількість невиконаних заявок і перевіряє, що сумарна куплена кількість дорівнює проданій.
3. Високий рівень. Створити консольний застосунок біржі з опціями --traders, --orders, --symbols AAPL,MSFT,…, --capacity, --seed, --trades файл.csv і --help. Заявки для різних акцій передаються окремими каналами до окремих споживачів-зіставлювачів, тож книги заявок не потребують блокувань. Програма записує журнал угод у CSV, виводить таблицю «акція – угод – обсяг – мінімальна, максимальна та середньозважена ціна» і час обробки; невідомі символи в заявках і некоректні опції повідомляються в потік помилок.
Варіант 8. Пошта з сортувальними центрами
1. Початковий рівень. Створити консольну програму з конвеєром із трьох етапів на BlockingCollection<T>: «приймання» створює 30 відправлень, «сортування» визначає область за індексом, а «доставка» виводить відправлення з назвою області. Кожен етап виконується в окремому потоці й закриває свою вихідну колекцію після завершення.
2. Базовий рівень. Створити консольну програму, яка запитує кількість відправлень, кількість сортувальників (1–8) і ємність черг, моделює конвеєр «приймання → сортування → доставка» з імітацією роботи кожного етапу й записує в кожне відправлення мітки часу входу на етап. Програма виводить таблицю «етап – середня затримка, мс – найбільша затримка, мс» і загальну пропускну здатність.
3. Високий рівень. Створити консольний застосунок, який читає відправлення з CSV-файлу (номер;індекс;вага) і приймає опції --sorters, --couriers, --capacity, --sort-ms, --deliver-ms та --help. Конвеєр на каналах має три етапи з налаштовуваною кількістю обробників. Програма виводить таблицю затримок кожного етапу (середня, медіана, 95-й процентиль), визначає вузьке місце (етап з найбільшим очікуванням у черзі) і пропонує, скільки обробників додати. Відправлення з некоректним індексом потрапляють в окремий файл помилок.
Варіант 9. Хибне розділення в гістограмі
1. Початковий рівень. Створити консольну програму, яка будує гістограму зі 100 кошиків для 50 мільйонів псевдовипадкових чисел від 0 до 99 у 4 потоках двома способами: усі потоки збільшують елементи спільного масиву long[,] «потік × кошик», і кожен потік заповнює локальний масив, який копіюється наприкінці. Вивести час обох способів і ознаку збігу гістограм.
2. Базовий рівень. Створити консольну програму, яка запитує кількість псевдовипадкових чисел і кількість кошиків гістограми та вимірює побудову гістограми для 1, 2, 4 і 8 потоків трьома способами: спільний масив лічильників потоків, локальні гістограми зі злиттям, спільний масив з Interlocked.Increment. Для кожного способу виконується прогрівання та медіана п’яти запусків; програма виводить таблицю часу й прискорення та перевіряє, що всі гістограми дорівнюють послідовній.
3. Високий рівень. Створити консольний застосунок на BenchmarkDotNet, який порівнює способи паралельної побудови гістограми псевдовипадкових чисел (спільний масив лічильників, доповнені структури [StructLayout], локальні гістограми) з параметрами [Params]: 1, 2, 4, 8 потоків і 16 та 1 024 кошики. Режим --quick вимірює через Stopwatch без BenchmarkDotNet. Програма перевіряє коректність гістограм перед вимірюваннями, виводить таблицю результатів і пояснює, у якому способі прискорення найбільше.
Варіант 10. Транспортні валідатори
1. Початковий рівень. Створити консольну програму, у якій 5 потоків-валідаторів генерують по 1 000 подій проїзду (номер маршруту 1–10, вартість 8, 15 або 30 грн) і додають їх у ConcurrentQueue<Trip>, а потік-агрегатор після завершення валідаторів рахує кількість поїздок і виторг за кожним маршрутом.
2. Базовий рівень. Створити консольну програму, яка запитує кількість валідаторів, подій і число N, передає події проїзду через канал агрегатору, а агрегатор кожні N подій виводить проміжний звіт «маршрут – поїздок – виторг» і наприкінці підсумковий. Програма перевіряє, що сума виторгу у звіті дорівнює сумі вартостей усіх згенерованих подій.
3. Високий рівень. Створити консольний застосунок, який читає події з кількох CSV-файлів (час;валідатор;маршрут;тариф, один файл на валідатор) і приймає опції --every N, --routes файл (назви маршрутів), --out теку і --help. Читачі файлів пишуть в обмежений канал, агрегатор будує звіти кожні N подій і записує їх в окремі файли, а підсумок містить таблицю маршрутів за спаданням виторгу з рядком «Разом» і годину пік для кожного маршруту. Невідомі маршрути й тарифи повідомляються в потік помилок, код завершення 2 – якщо жодної події не прочитано.
Варіант 11. Службова черга друку
1. Початковий рівень. Створити консольну програму, у якій 4 користувачі-потоки надсилають по 5 завдань друку (назва документа, кількість сторінок) в BlockingCollection<PrintJob> ємністю 5, а два принтери друкують їх зі швидкістю 20 мс на сторінку. Програма виводить журнал друку та загальну кількість надрукованих сторінок.
2. Базовий рівень. Створити консольну програму, яка запитує кількість користувачів, принтерів, завдань і ємність черги та дозволяє скасувати завдання: окремий потік скасовує кожне п’яте завдання до початку друку (прапорець у завданні, який принтер перевіряє). Додавання виконується методом TryAdd з тайм-аутом 100 мс, відмови рахуються. Програма виводить таблицю «принтер – завдань – сторінок», кількість скасованих і відхилених завдань.
3. Високий рівень. Створити консольний застосунок черги друку з опціями --printers, --capacity, --ppm сторінок/хв, --jobs файл.csv і --help, де файл містить час;користувач;документ;сторінки. Принтери беруть завдання з тайм-аутом і CancellationToken, що дозволяє зупинити всю чергу за натисканням Q. Застосунок виводить таблицю «користувач – завдань – сторінок – середнє очікування, с», завантаженість кожного принтера й кількість завдань, що залишилися в черзі після зупинки. Некоректні рядки файлу повідомляються в потік помилок з номером рядка.
Варіант 12. Каталог товарів
1. Початковий рівень. Створити консольну програму, яка створює каталог із 10 000 товарів (артикул і ціна) як FrozenDictionary<string, decimal> і в 8 потоках виконує по 1 000 000 пошуків випадкових артикулів. Програма виводить час пошуку та порівнює його з тим самим навантаженням для ConcurrentDictionary<string, decimal>.
2. Базовий рівень. Створити консольну програму, у якій 8 потоків-покупців безперервно шукають ціни в каталозі FrozenDictionary<string, decimal>, а потік-адміністратор кожні 200 мс змінює ціни 1 % товарів, будує новий заморожений каталог і атомарно замінює посилання методом Interlocked.Exchange. Кожна версія каталогу має номер. Програма виводить кількість пошуків, кількість версій і перевіряє, що кожен покупець бачив лише цілісні версії (ціни одного знімка з однаковим номером версії).
3. Високий рівень. Створити консольний застосунок, який завантажує каталог з CSV-файлу (артикул;назва;ціна) і приймає опції --readers, --duration с, --update-ms, --updates файл (зміни цін) і --help. Застосунок вимірює пропускну здатність пошуку для Dictionary<TKey, TValue> під ReaderWriterLockSlim, ConcurrentDictionary<TKey, TValue> та FrozenDictionary<TKey, TValue> з атомарною заміною і виводить таблицю «структура – пошуків/с – час побудови версії, мс». Дублікати артикулів і некоректні ціни повідомляються в потік помилок; код завершення 2, якщо каталог порожній.
Варіант 13. Лабораторні аналізи
1. Початковий рівень. Створити консольну програму, яка розподіляє 30 зразків аналізів (пацієнт, тип: кров, сеча, біохімія) у три канали за типом, а три потоки-лаборанти обробляють «свої» канали з різною тривалістю. Програма виводить, коли і хто обробив кожен зразок.
2. Базовий рівень. Створити консольну програму, яка запитує кількість пацієнтів і для кожного генерує 2–4 аналізи різних типів, передає їх у канали за типами, а після обробки об’єднує результати за пацієнтом в ConcurrentDictionary<int, List<Result>> із синхронізацією доступу до списків. Програма виводить картку кожного пацієнта з результатами та перевіряє, що кожен аналіз виконано рівно один раз.
3. Високий рівень. Створити консольний застосунок, який читає направлення з CSV-файлу (пацієнт;аналіз1,аналіз2,…) і приймає опції --lab тип=кількість (кілька разів, наприклад --lab кров=2), --capacity і --help. Для кожного типу аналізу створюється обмежений канал і задана кількість лаборантів; результати збираються етапом об’єднання, який видає картку пацієнта, коли готові всі його аналізи. Програма виводить таблицю «тип – аналізів – середній час у черзі – завантаженість» і записує картки пацієнтів у файли. Невідомі типи аналізів повідомляються в потік помилок.
Варіант 14. Метеорологічні архіви
1. Початковий рівень. Створити консольну програму, яка генерує CSV-файл із 200 000 рядків дата;станція;температура, а потім читає його в одному потоці та розбирає рядки в чотирьох потоках через BlockingCollection<string>, обчислюючи середню температуру кожної станції. Вивести результат і час обробки.
2. Базовий рівень. Створити консольну програму, яка запитує шлях до CSV-файлу метеоархіву та перелік ємностей черги (наприклад, 10 100 1000 10000) і для кожної ємності обробляє файл конвеєром «читання → розбір (4 потоки) → агрегація». Програма виводить таблицю «ємність – час, мс – найбільше елементів у черзі» та середні, мінімальні й максимальні температури станцій, перевірені послідовною обробкою.
3. Високий рівень. Створити консольний застосунок, який обробляє теку CSV-файлів метеоархіву з опціями --parsers 1,2,4,8, --capacity 16,256,4096, --batch N (передавання рядків пакетами) і --help. Для кожної комбінації параметрів програма вимірює медіану трьох запусків і виводить таблицю «розбирачів – ємність – пакет – час, мс – прискорення», а також щомісячну статистику станцій у файл. Рядки з некоректними датами або температурами поза межами −90…+60 °C пропускаються з лічильником помилок.
Варіант 15. Ігрові рекорди
1. Початковий рівень. Створити консольну програму, у якій 8 потоків-ігрових серверів надсилають по 10 000 результатів (гравець з 50 імен, очки) у спільний ConcurrentDictionary<string, int>, зберігаючи найкращий результат кожного гравця методом AddOrUpdate. Програма виводить десятку найкращих і перевіряє результат послідовним підрахунком.
2. Базовий рівень. Створити консольну програму, яка запитує кількість серверів і результатів, зберігає профілі гравців у ConcurrentDictionary<string, Lazy<Profile>>, де створення профілю імітує завантаження з бази (100 мс, лічильник викликів), і оновлює рекорди атомарно. Програма виводить рейтинг, кількість створених профілів (має дорівнювати кількості гравців) і для порівняння кількість викликів фабрики без Lazy<T>.
3. Високий рівень. Створити консольний застосунок для стрес-тесту таблиці рекордів з опціями --servers, --players, --results, --mode lock|concurrent|lazy і --help. Для кожного режиму програма виконує навантаження, перевіряє інваріанти (рекорд гравця дорівнює максимуму його результатів, профіль створено один раз) і виводить таблицю «режим – потоків – час, мс – операцій/с – порушень». Код завершення 0, якщо порушень немає, 3 – якщо є, 1 – помилка аргументів.
Варіант 16. Кол-центр
1. Початковий рівень. Створити консольну програму, у якій потік-генератор додає 40 дзвінків (номер абонента, тривалість 10–100 мс) у ConcurrentQueue<Call>, а чотири оператори в циклі беруть дзвінки методом TryDequeue і «розмовляють» відповідну тривалість. Програма виводить кількість дзвінків кожного оператора.
2. Базовий рівень. Створити консольну програму, яка запитує кількість операторів, кількість дзвінків і середній інтервал між ними, моделює кол-центр на ConcurrentQueue<Call> з мітками часу надходження та виводить середній і найбільший час очікування, кількість дзвінків кожного оператора та частку дзвінків, що чекали довше 1 с. Оператори завершуються, коли генератор закінчив роботу й черга порожня.
3. Високий рівень. Створити консольний застосунок, який читає з CSV-файлу розклад дзвінків (час_мс;абонент;тривалість_мс;тип) і приймає опції --operators 1-10, --sla секунд і --help. Для кожної кількості операторів з діапазону програма моделює роботу та виводить таблицю «операторів – середнє очікування – 95-й процентиль – частка в межах SLA, %», а також мінімальну кількість операторів, за якої частка дзвінків у межах SLA не менша за 90 %. Некоректні рядки повідомляються в потік помилок.
Варіант 17. Лічильники трафіку перехресть
1. Початковий рівень. Створити консольну програму, у якій 8 потоків моделюють камери перехресть і кожен збільшує свій лічильник автомобілів 50 мільйонів разів (кожне третє значення генератора – «автомобіль»). Лічильники зберігаються в масиві структур з одним полем long. Програма виводить час і загальну кількість автомобілів.
2. Базовий рівень. Створити консольну програму, у якій потоки-камери перехресть збільшують кожен свій лічильник автомобілів (кожне третє значення генератора – «автомобіль»). Програма запитує кількість камер (1–16) і подій та порівнює лічильники у звичайних структурах і в структурах з атрибутом [StructLayout(LayoutKind.Sequential, Size = 128)]. Для кожного варіанта – прогрівання й медіана п’яти запусків; вивести час, прискорення відносно одного потоку й перевірку суми лічильників.
3. Високий рівень. Створити консольний застосунок, у якому потоки-камери перехресть рахують автомобілі серед --events згенерованих подій, збільшуючи кожен свій лічильник, з опціями --cameras 1,2,4,8,16, --layout plain|padded|local|all (звичайні структури, доповнені до 128 байтів, локальні змінні), --csv і --help. Для кожної кількості камер і розміщення лічильників програма виводить таблицю «камер – час, мс – прискорення – ефективність», записує CSV, виводить розмір структури (Unsafe.SizeOf<T>()) і висновок, яке розміщення найефективніше на 8 потоках.
Варіант 18. Конвертер одиниць вимірювання у файлах
1. Початковий рівень. Створити консольну програму, яка читає текстовий файл зі значеннями в дюймах (по одному в рядку), передає їх через BlockingCollection<string> потоку-перетворювачу, а той – через другу колекцію потоку-записувачу, який записує значення в сантиметрах у новий файл. Програма виводить кількість перетворених рядків.
2. Базовий рівень. Створити консольну програму, яка запитує вхідний і вихідний файли та кількість перетворювачів, читає рядки значення одиниця (in, ft, mi, lb, °F) і перетворює їх у метричні одиниці конвеєром «читання → перетворення → запис» на каналах. Порядок рядків у вихідному файлі має збігатися з вхідним (номер рядка передається разом зі значенням, записувач упорядковує результати). Програма виводить статистику за одиницями та кількість помилкових рядків.
3. Високий рівень. Створити консольний застосунок convert з аргументами вхідний_файл вихідний_файл та опціями --to metric|imperial, --workers, --capacity, --errors файл і --help. Конвеєр на обмежених каналах зберігає порядок рядків, записує нерозпізнані рядки у файл помилок з номерами й причинами і завершує всі етапи навіть тоді, коли один з перетворювачів згенерував виняток (Complete з винятком). Програма виводить таблицю «одиниця – рядків – перетворено» і час; код завершення 2, якщо частка помилок перевищує 10 %.
Варіант 19. Аукціон
1. Початковий рівень. Створити консольну програму, у якій 5 потоків-учасників аукціону протягом 2 с записують ставки (учасник, сума) у канал Channel<Bid>, а потік-аукціоніст читає ставки, приймає лише ті, що більші за поточну найвищу, і після закриття каналу виводить переможця та кількість прийнятих і відхилених ставок.
2. Базовий рівень. Створити консольну програму, яка запитує кількість учасників, стартову ціну, крок ставки й тривалість аукціону в секундах. Ставки передаються аукціоністу через канал з міткою часу; ставки, створені після завершення аукціону, вважаються пізніми й відхиляються. Програма виводить історію прийнятих ставок, переможця, кількість відхилених ставок окремо за причинами (мала сума, пізня ставка).
3. Високий рівень. Створити консольний застосунок, який проводить кілька аукціонів лотів одночасно (лоти з CSV-файлу лот;стартова_ціна;крок;тривалість_с) з опціями --bidders, --seed, --log файл і --help. Кожен лот має власний канал ставок і аукціоніста; учасники стратегічно роблять ставки на кілька лотів у межах бюджету. Програма виводить таблицю «лот – переможець – ціна – ставок – пізніх ставок» і перевіряє, що жоден учасник не перевищив бюджет. Некоректні рядки лотів повідомляються в потік помилок.
Варіант 20. Неблокуючий стек завдань
1. Початковий рівень. Створити консольну програму з неблокуючим стеком Трейбера на Interlocked.CompareExchange, у який 4 потоки додають по 100 000 завдань (номерів), а потім 4 потоки вилучають їх. Програма перевіряє, що кількість і сума вилучених номерів дорівнюють доданим.
2. Базовий рівень. Створити консольну програму, яка запитує кількість потоків і операцій та виконує змішане навантаження (50 % Push, 50 % TryPop) для стеку Трейбера і ConcurrentStack<T>. Стек Трейбера рахує кількість невдалих спроб CAS. Програма виводить таблицю «стек – час, мс – операцій/с – повторів CAS» і перевіряє, що жоден елемент не загубився й не був вилучений двічі.
3. Високий рівень. Створити консольний застосунок на BenchmarkDotNet, який порівнює стек Трейбера, ConcurrentStack<T> і Stack<T> під блокуванням Lock для 1, 2, 4 і 8 потоків та співвідношень Push/TryPop 90/10, 50/50 і 10/90. Режим --verify запускає без BenchmarkDotNet стрес-тест із перевіркою інваріантів для кожної реалізації (кількість, сума, відсутність дублікатів) і завершується кодом 3 у разі порушення. Застосунок виводить таблицю результатів і коротке пояснення, коли неблокуючий стек виграє.
Варіант 21. Бібліотечні видачі
1. Початковий рівень. Створити консольну програму, у якій стан видач книг зберігається в ImmutableDictionary<string, string> («книга – читач»), а 4 потоки-бібліотекарі видають і повертають книги через ImmutableInterlocked.TryAdd та ImmutableInterlocked.TryRemove. Програма виводить підсумковий стан і кількість успішних та відхилених операцій.
2. Базовий рівень. Створити консольну програму, яка запитує кількість книг, читачів і операцій та моделює видачі в кількох потоках з незмінним словником. Кожна успішна зміна додає версію стану в незмінний стек історії (ImmutableInterlocked.Push). Програма дозволяє після моделювання ввести номер версії та виводить стан видач на той момент, а також перевіряє, що жодна книга ніколи не була видана двом читачам одночасно.
3. Високий рівень. Створити консольний застосунок бібліотеки з командами у файлі сценарію (видати книга читач, повернути книга, відкат N) і опціями --threads, --snapshot-every N та --help. Сценарій виконується кількома потоками, оновлення стану атомарні, а команда відкат повертає стан на N версій назад без втрати пізніших записів історії. Програма виводить таблицю «читач – книг на руках», кількість версій, розмір історії та помилкові команди в потік помилок.
Варіант 22. Завантаження відеофрагментів (імітація)
1. Початковий рівень. Створити консольну програму, у якій потік-завантажувач «отримує» 100 фрагментів відео (затримка 5 мс) і записує їх в обмежений канал ємністю 8, а споживач-декодер обробляє кожен фрагмент 20 мс. Програма виводить, скільки разів завантажувач чекав на місце в каналі (WaitToWriteAsync після невдалого TryWrite), і загальний час.
2. Базовий рівень. Створити консольну програму-модель відеопрогравача, яка запитує кількість фрагментів, ємність каналу, час завантаження й декодування фрагмента. Завантажувач записує фрагменти в обмежений канал, декодер читає їх. Програма виводить середнє й найбільше заповнення каналу, сумарний час очікування завантажувача і кількість «зупинок відтворення» (декодер чекав на фрагмент довше 50 мс).
3. Високий рівень. Створити консольний застосунок-модель відеопрогравача, у якому завантажувач записує --segments фрагментів з випадковою затримкою --download-ms мін-макс в обмежений канал, а --decoders декодерів читають їх. Для кожної ємності з --capacity 2,4,8,16,32 програма виводить таблицю «ємність – зупинок відтворення – середнє заповнення – пам’ять фрагментів, МБ – час, с» і рекомендує найменшу ємність без зупинок. Опції --seed, --help; некоректні діапазони – у потік помилок з кодом 1.
Варіант 23. Моніторинг серверів
1. Початковий рівень. Створити консольну програму, у якій 3 потоки-сервери щосекунди протягом 10 с записують у канал метрику завантаження процесора (випадкове значення 0–100 %), а споживач виводить кожне значення та повідомлення, якщо завантаження перевищує 90 %.
2. Базовий рівень. Створити консольну програму, яка запитує кількість серверів, розмір вікна ковзного середнього й поріг, передає метрики через канал і для кожного сервера обчислює ковзне середнє. Сповіщення формується лише тоді, коли ковзне середнє перевищує поріг, і повторно – лише після повернення нижче порогу. Програма виводить журнал сповіщень і таблицю «сервер – середнє – максимум – сповіщень».
3. Високий рівень. Створити консольний застосунок моніторингу з опціями --servers, --metrics cpu,ram,disk, --window, --threshold метрика=значення, --duration і --help. Метрики кожного типу передаються окремими каналами до окремих аналізаторів, а сповіщення – спільним каналом до потоку журналу, який записує їх у файл і виводить на екран. Наприкінці програма виводить таблицю «сервер – метрика – середнє – 95-й процентиль – сповіщень» і коректно завершує всі етапи за натисканням Ctrl+C.
Варіант 24. Сортування посилок
1. Початковий рівень. Створити консольну програму, у якій 4 потоки-сортувальники обробляють 1 000 посилок з ConcurrentQueue<Parcel> і складають їх у ConcurrentBag<Parcel> відповідного регіону (Північ, Південь, Схід, Захід, Центр). Програма виводить кількість посилок у кожному регіоні й перевіряє загальну кількість.
2. Базовий рівень. Створити консольну програму, яка запитує кількість посилок і сортувальників, розкладає посилки в ConcurrentBag<Parcel> за регіонами, а потім запускає для кожного регіону кур’єрів, кількість яких пропорційна кількості посилок регіону. Кур’єри беруть посилки методом TryTake. Програма виводить таблицю «регіон – посилок – кур’єрів – посилок на кур’єра» та перевіряє, що кожну посилку доставлено один раз.
3. Високий рівень. Створити консольний застосунок, який читає посилки з CSV-файлу (номер;регіон;вага) і приймає опції --sorters, --couriers, --balance none|proportional|steal і --help. У режимі steal кур’єр, що звільнився, бере посилки з мішків інших регіонів. Для кожного режиму програма виводить час доставлення, найбільшу й найменшу кількість посилок на кур’єра та коефіцієнт нерівномірності навантаження; невідомі регіони повідомляються в потік помилок.
Варіант 25. Обробка платежів
1. Початковий рівень. Створити консольну програму, у якій потік-виробник додає 100 платежів у BlockingCollection<Payment?>, а наприкінці – по одному значенню null («отруйна пігулка») для кожного з трьох споживачів. Споживач завершується, отримавши null. Програма виводить кількість і суму платежів кожного споживача та загальну суму.
2. Базовий рівень. Створити консольну програму, яка запитує кількість виробників, споживачів і платежів та реалізує завершення двома способами: «отруйні пігулки» і CompleteAdding. Для «отруйних пігулок» їх додають лише після завершення всіх виробників. Програма виводить для кожного способу кількість оброблених платежів, загальну суму та ознаку, що всі споживачі завершилися за 5 с (Join з тайм-аутом).
3. Високий рівень. Створити консольний застосунок обробки платежів з файлу (рахунок;сума;валюта) з опціями --consumers, --capacity, --fail-rate % і --help. Споживач може згенерувати виняток на окремому платежі (імітація збою): такий платіж переходить у чергу повторів, а після трьох невдач – у файл відхилених. Застосунок гарантує завершення всіх споживачів навіть після винятків (try/finally) і виводить таблицю «валюта – платежів – сума – повторів – відхилено» та звіт про звірку сум.
Варіант 26. Словник синонімів
1. Початковий рівень. Створити консольну програму, яка створює словник синонімів із 5 000 слів як ImmutableDictionary<string, string[]> і в 8 потоках виконує по 500 000 пошуків випадкових слів. Вивести час пошуку та кількість знайдених слів.
2. Базовий рівень. Створити консольну програму, яка запитує кількість слів і потоків та порівнює швидкість читання синонімів для ImmutableDictionary<TKey, TValue>, ConcurrentDictionary<TKey, TValue> та FrozenDictionary<TKey, TValue>, поки окремий потік раз на 100 мс додає нове слово (для незмінного словника – через ImmutableInterlocked.AddOrUpdate, для замороженого – перебудовою). Програма виводить таблицю «структура – пошуків/с – оновлень».
3. Високий рівень. Створити консольний застосунок, який завантажує словник синонімів з файлу (слово: синонім1, синонім2) і вимірює пропускну здатність пошуку синонімів для ImmutableDictionary<TKey, TValue>, ConcurrentDictionary<TKey, TValue> і FrozenDictionary<TKey, TValue> з опціями --readers 1,2,4,8, --write-ratio 0,1,10 (відсоток записів), --duration і --help. Програма виводить таблицю з виділенням найкращої структури для кожного співвідношення читань і записів. Дублікати слів об’єднуються, порожні рядки пропускаються, помилки формату – у потік помилок.
Варіант 27. Лічильник голосів у регіонах
1. Початковий рівень. Створити консольну програму, у якій 8 потоків (по одному на регіон) рахують голоси за трьох кандидатів у масиві 80 мільйонів бюлетенів (зерно 5) і збільшують поля спільної структури RegionVotes { long A, B, C; } у масиві регіонів. Вивести результати кандидатів і час.
2. Базовий рівень. Створити консольну програму, яка запитує кількість бюлетенів і регіонів та рахує голоси трьома способами: поля структур у спільному масиві, доповнені структури (StructLayout розміром 128 байтів), локальні змінні із записом наприкінці. Програма виводить таблицю «спосіб – час для 1, 2, 4, 8 потоків» і перевіряє, що результати всіх способів однакові.
3. Високий рівень. Створити консольний застосунок, який читає бюлетені з бінарного файлу (байт – кандидат 0–9, генерується опцією --generate N) і приймає опції --regions 1,2,4,8,16, --method shared|padded|local|all, --runs та --help. Програма виводить таблицю «метод – регіонів – медіана, мс – прискорення – ефективність», визначає, для якого методу ефективність на 8 потоках падає нижче 50 %, і виводить підсумкові результати виборів з відсотками. Пошкоджені байти (значення поза 0–9) рахуються окремо.
Варіант 28. Шкільний електронний журнал
1. Початковий рівень. Створити консольну програму, яка генерує 1 000 рядків оцінок клас;учень;предмет;оцінка, передає їх через BlockingCollection<string> двом потокам перевірки (оцінка 1–12) і складає правильні записи в ConcurrentBag<Grade>. Програма виводить кількість правильних і помилкових рядків.
2. Базовий рівень. Створити консольну програму, яка запитує шлях до CSV-файлу оцінок і кількість перевіряльників, імпортує оцінки конвеєром «читання → перевірка → агрегація» на каналах і виводить таблицю «клас – предмет – середня оцінка – кількість оцінок» та перелік помилок з номерами рядків (порожнє ім’я, оцінка поза 1–12, невідомий предмет).
3. Високий рівень. Створити консольний застосунок імпорту оцінок з кількох файлів (по одному на клас) з опціями --subjects файл, --validators N, --report теку і --help. Конвеєр на обмежених каналах перевіряє оцінки, агрегує їх за учнями й предметами та формує для кожного класу звіт у файл: середні оцінки учнів, середні за предметами, п’ять найкращих учнів. Програма виводить зведену таблицю класів, кількість помилок за типами та повертає код 2, якщо помилкових рядків більше 5 %.
Варіант 29. Обмін криптоцін (імітація)
1. Початковий рівень. Створити консольну програму, у якій потік-біржа протягом 3 с без затримок записує котирування (валюта, ціна) методом TryWrite в канал ємністю 100 з режимом DropOldest, а споживач обробляє котирування 1 мс. Програма виводить кількість створених, оброблених і втрачених котирувань та останню ціну.
2. Базовий рівень. Створити консольну програму, яка запитує кількість валют, частоту котирувань, ємність каналу й затримку споживача, моделює потік котирувань із режимом DropOldest і рахує втрачені котирування делегатом itemDropped. Програма виводить таблицю «валюта – створено – оброблено – втрачено, % – остання ціна» і перевіряє, що остання оброблена ціна кожної валюти збігається з останньою створеною.
3. Високий рівень. Створити консольний застосунок з опціями --pairs BTC,ETH,…, --rate, --capacity, --mode DropOldest|DropNewest|DropWrite|Wait, --consumer-ms, --duration і --help, який для кожного режиму моделює обмін і обчислює «застарілість» котирувань (різницю між часом обробки та часом створення). Програма виводить таблицю «режим – втрачено, % – середня застарілість, мс – найбільша застарілість, мс» і пояснює, який режим кращий для відображення поточних цін.
Варіант 30. Генерація звітів
1. Початковий рівень. Створити консольну програму, у якій потік-виробник додає 50 завдань генерації звітів (тривалість 20–200 мс) у BlockingCollection<ReportJob>, а пул із трьох потоків обробляє їх. Програма щосекунди виводить довжину черги та кількість виконаних завдань.
2. Базовий рівень. Створити консольну програму, яка запитує кількість завдань, мінімальний і максимальний розмір пулу та поріг довжини черги. Потік-наглядач кожні 200 мс перевіряє довжину черги: якщо вона перевищує поріг, запускає ще одного обробника (до максимуму), а якщо черга порожня – зупиняє зайвого обробника (до мінімуму) через окремий сигнал. Програма виводить журнал змін розміру пулу й середній час очікування завдань.
3. Високий рівень. Створити консольний застосунок з опціями --min, --max, --scale-up черга, --scale-down черга, --jobs файл.csv (час_мс;тип;тривалість_мс) і --help, який моделює службу звітів з пулом споживачів змінного розміру над обмеженим каналом. Програма порівнює фіксований пул мінімального і максимального розміру з адаптивним і виводить таблицю «стратегія – середнє очікування – 95-й процентиль – потоко-секунд» та графік довжини черги в текстовому вигляді; помилки аргументів – код завершення 1.
Порядок виконання та захисту роботи
- Опрацювати теоретичні відомості та приклади розв’язання завдань.
- Для свого варіанта визначити спільні дані, виробників і споживачів, етапи конвеєра, ємність черг і спосіб завершення; накреслити схему потоків даних.
- Створити консольний проєкт у JetBrains Rider (.NET 10) і реалізувати завдання обраного рівня складності з потокобезпечними колекціями або каналами.
- Порівняти результат з послідовною версією, перевірити завершення за будь-якої кількості виробників і споживачів, виміряти час у Release для різної кількості потоків і перевірити програму на хибне розділення.
- Продемонструвати роботу програми викладачеві, пояснити вибір структур даних і результати вимірювань, відповісти на контрольні питання.