Підрозділ 16.Q
Питання для самоконтролю
Питання для самоконтролю — Розділ 16. Паралельне програмування та TPL 16.1. Клас Task. Основи TPL 1. Що таке TPL і яку проблему вона вирішує порівняно з прямим використанням класу Thread ? Поясніть концепцію пу
Питання для самоконтролю — Розділ 16. Паралельне програмування та TPL
16.1. Клас Task. Основи TPL
Що таке TPL і яку проблему вона вирішує порівняно з прямим використанням класу
Thread? Поясніть концепцію пулу потоків (ThreadPool) і чому він ефективніший за постійне створення нових потоків.Порівняйте три способи створення завдання:
new Task(...) + Start(),Task.Factory.StartNew()іTask.Run(). Коли кожен з них є доцільним вибором?Що виведе наступний код? Чи гарантований порядок виводу?
Task t = Task.Run(() => { Console.WriteLine($"Task: {Task.CurrentId}"); }); Console.WriteLine("Main before Wait"); t.Wait(); Console.WriteLine("Main after Wait");Поясніть різницю між
Task.WaitAllіTask.WaitAny. Для яких клінічних сценаріїв підходить кожен? Що повертаєWaitAnyі що відбувається з рештою завдань після повернення?Які стани описує перерахування
TaskStatus? Намалюйте (або опишіть словами) граф переходів між станами відCreatedдо термінального стану.Що відбудеться, якщо завдання кине виняток, а виклик
Wait()відбудеться? Яким типом буде виняток, що прилетить доcatch? Як отримати оригінальне повідомлення про помилку?Що робить
Task.RunSynchronously()? В яких сценаріях він корисний і що є його обмеженнями?Метод
Task.CurrentIdповертаєnullпоза завданням. Напишіть невеликий приклад, що демонструє, деTask.CurrentIdдорівнюєnull, а де — числовому значенню.
16.2. Вкладені завдання та масиви завдань. Task
Що таке вкладене (nested) завдання і яка його поведінка за замовчуванням щодо батьківського? Чому батьківське завдання може завершитись раніше вкладеного?
Що означає
TaskCreationOptions.AttachedToParent? Як ця опція змінює взаємозалежність між батьківським і дочірнім завданням? Як поширюються виключення дочірнього завдання?Порівняйте поведінку наступних двох фрагментів:
// Фрагмент A Task parent = Task.Factory.StartNew(() => { Task.Factory.StartNew(() => { Thread.Sleep(500); Console.WriteLine("Inner"); }); Console.WriteLine("Outer done"); }); parent.Wait(); Console.WriteLine("Main done"); // Фрагмент B — те саме, але з AttachedToParent Task parent = Task.Factory.StartNew(() => { Task.Factory.StartNew(() => { Thread.Sleep(500); Console.WriteLine("Inner"); }, TaskCreationOptions.AttachedToParent); Console.WriteLine("Outer done"); }); parent.Wait(); Console.WriteLine("Main done");Опишіть порядок виводу для обох фрагментів.
Що повертає властивість
ResultуTask<T>? Чому звернення доResultможе заблокувати поточний потік? Коли звернення доResultпісляTask.WaitAllне є блокуючим?Напишіть код, що паралельно запускає три
Task<string>, потім черезTask.WaitAllчекає завершення всіх і виводить результати у порядку їх оголошення (не обов'язково завершення).Розробіть клас
LabResultз полямиPatientName,Glucose,Hemoglobinі методTask<LabResult> RunLabAsync(string name). Запустіть завдання для 4 пацієнтів паралельно, дочекайтесь всіх і виведіть зведену таблицю результатів.Якщо один із Task у масиві
Task<T>[]завершився з виключенням, що станеться при зверненні доtask.ResultпісляWaitAll? Як безпечно отримати результати тільки успішних завдань?
16.3. Продовження завдань. ContinueWith
Що таке завдання-продовження (continuation task)? Яку перевагу воно дає над
Wait()+ новийTask.Run()?Який параметр отримує делегат у
ContinueWith? Що через нього можна дізнатись про попереднє завдання?Що виведе наступний код і в якому порядку?
Task<int> t = Task.Run(() => { Thread.Sleep(100); return 42; }); Task t2 = t.ContinueWith(prev => Console.WriteLine($"Результат: {prev.Result}")); t2.Wait(); Console.WriteLine("Головний потік");Поясніть
TaskContinuationOptions.OnlyOnRanToCompletionіTaskContinuationOptions.OnlyOnFaulted. У якому стані опиниться продовження, якщо умова не виконалась? Яке виключення кинеWaitAllу цьому випадку?Побудуйте ланцюг із чотирьох кроків через
ContinueWith(реєстрація → огляд → аналізи → призначення), де кожен крок повертає результат типуstring, що передається наступному. ВикористовуйтеTask<string>іContinueWith<string>.Що таке
TaskCompletionSource<T>? У яких трьох сценаріях він корисний? Поясніть різницю міжSetResultіTrySetResult.Реалізуйте функцію
Task<string> WrapCallbackAsync(Action<string> callback), що перетворює callback-based API в Task-based за допомогоюTaskCompletionSource. Покажіть, якSetResultіSetExceptionвідповідають різним сценаріям callback.Знайдіть потенційну проблему в наступному коді:
Task step1 = Task.Run(() => throw new Exception("fail")); Task step2 = step1.ContinueWith(t => Console.WriteLine("Success")); step2.Wait();Чи виконається
step2? Чому? Як виправити за допомогоюTaskContinuationOptions?
16.4. Клас Parallel
Яка головна відмінність між
Parallelі ручним управлінням завданнями черезTask.Run? У яких сценаріяхParallelє зручнішим вибором?Що гарантує
Parallel.Invokeщодо завершення переданих дій? Чи гарантується порядок виконання? Чи гарантується, що кожна дія виконається в окремому потоці?Порівняйте
Parallel.ForіParallel.ForEach. Яка різниця в типах даних, з якими вони працюють? Що повертаєParallelLoopResultі які його властивості?Що станеться, якщо написати
breakу тілі лямбди уParallel.For? Як правильно перервати виконання паралельного циклу?Поясніть різницю між
ParallelLoopState.Break()іParallelLoopState.Stop(). Після якого методуIsCompletedбудеfalse? КолиLowestBreakIterationмає значення?Що означає
MaxDegreeOfParallelism = 1уParallelOptions? Коли це корисно? Що означаєMaxDegreeOfParallelism = -1?Знайдіть проблему в наступному коді і поясніть, як її виправити:
int total = 0; Parallel.For(0, 1000, i => { total++; // небезпечно }); Console.WriteLine(total);Спроєктуйте паралельне обчислення ризику для списку пацієнтів через
Parallel.ForEach. Реалізуйте зупинку при виявленні першого пацієнта з критичним показником черезParallelLoopState.Stop(). Чому після зупинки результат може містити пацієнтів з індексом вище за той, на якому викликалиStop()?
16.5. Скасування завдань. CancellationToken
Що таке кооперативне скасування? Чому
Thread.Abort()є небезпечним і чому він вилучений з .NET 5+?Поясніть розподіл ролей між
CancellationTokenSourceіCancellationToken. Чому завдання отримує лишеCancellationToken, а неCancellationTokenSource?У чому різниця між м'яким скасуванням (через
IsCancellationRequested) і жорстким (черезThrowIfCancellationRequested)? Який стан отримає Task після кожного варіанту скасування —RanToCompletionчиCanceled?Що виведе наступний код?
CancellationTokenSource cts = new CancellationTokenSource(); Task task = Task.Run(() => { for (int i = 0; i < 10; i++) { cts.Token.ThrowIfCancellationRequested(); Thread.Sleep(100); Console.WriteLine($"Step {i}"); } }, cts.Token); Thread.Sleep(250); cts.Cancel(); try { task.Wait(); } catch (AggregateException ae) { Console.WriteLine(ae.InnerException?.GetType().Name); } Console.WriteLine(task.Status);Що робить
CancellationToken.Register()? У якому потоці виконується зареєстрований делегат? Для яких задач він корисний?Як реалізувати тайм-аут для завдання за допомогою
CancelAfter? Напишіть приклад, де завдання скасовується через 500 мс, якщо не завершилось раніше.Що таке пов'язані токени (
CreateLinkedTokenSource)? Наведіть приклад, де операція може бути скасована двома незалежними причинами: за тайм-аутом і за запитом користувача. Як після скасування визначити, яка саме причина спрацювала?Передайте
CancellationTokenуParallel.ForEachчерезParallelOptions. Яке виключення кинеParallelпри скасуванні? Порівняйте це з поведінкою при скасуванні звичайногоTask.Run().