OOP Course
Сьогодні

Підрозділ 17.5

Скасування async-операцій. CancellationToken

17.5. Скасування async операцій. CancellationToken Скасування — невід'ємна частина асинхронного програмування. Користувач натискає «Скасувати», сплив тайм аут, програма завершує роботу — у всіх цих випадках пот

17.5. Скасування async-операцій. CancellationToken

Скасування — невід'ємна частина асинхронного програмування. Користувач натискає «Скасувати», сплив тайм-аут, програма завершує роботу — у всіх цих випадках потрібно коректно зупинити async-операцію, що виконується. CancellationToken у async-контексті працює за тим самим кооперативним принципом, що і у TPL (розділ 16.5), але має ряд async-специфічних особливостей.

Скасування async-операцій через CancellationToken

CancellationToken у async-методах

Async-метод приймає CancellationToken як параметр — за угодою, останній або передостанній. Токен передається у вбудовані async-методи (.NET BCL весь побудований на цій угоді), а також перевіряється вручну між операціями:

Task.Delay(ms, token) — async-версія затримки зі скасуванням. Коли токен скасовується, Task.Delay кидає OperationCanceledException одразу, не чекаючи завершення таймера.

Перевірка токену між операціями

У довгих async-методах, що виконують кілька кроків, важливо перевіряти токен між кроками — щоб не починати нову операцію після сигналу скасування:

ct.ThrowIfCancellationRequested() — синхронна перевірка, що кидає OperationCanceledException без затримки. Розміщуйте її на початку кожного кроку або ітерації.

CancelAfter — тайм-аут для async-операцій

CancellationTokenSource.CancelAfter(ms) — стандартний спосіб реалізації тайм-ауту для async-операцій. Замість складних конструкцій з Task.WhenAny + Task.Delay, він пряно і чисто обмежує час операції:

Конструктор new CancellationTokenSource(ms) — скорочення для CancelAfter(ms). Для сучасного async-коду це набагато зручніше, ніж ручна конструкція з Task.WhenAny.

Пов'язані токени у async-контексті

Реальні системи часто мають кілька незалежних причин для скасування: глобальний тайм-аут застосунку, тайм-аут конкретного запиту, та сигнал від користувача. CancellationTokenSource.CreateLinkedTokenSource об'єднує кілька токенів — новий токен спрацьовує при скасуванні будь-якого:

Пов'язані токени — ключовий інструмент для ієрархічного скасування: батьківський scope (застосунок) → дочірній scope (запит) → конкретна операція.

Передача токену у бібліотечні async-методи

Більшість async-методів у .NET BCL приймають CancellationToken. Завжди передавайте токен — це гарантує коректне скасування на кожному рівні:

Коректна відповідь на скасування: OperationCanceledException

Коли операція скасовується, правильна поведінка — перекинути OperationCanceledException (або TaskCanceledException), а не повернути пустий результат чи ковтнути виняток. Це дозволяє коду вище в стеку знати, що операція не просто завершилась — вона була скасована:

Конструкція catch (OperationCanceledException) when (!globalCt.IsCancellationRequested) — фільтр виключень. Вона перехоплює скасування тільки від тайм-ауту спроби, але пропускає через себе скасування від глобального токену. Це точний контроль над тим, яке саме скасування обробляється.

Стан Task після скасування

Async-метод, скасований через OperationCanceledException, переходить у стан Canceled — якщо токен, що спричинив виняток, був переданий у Task при його старті. Якщо ж виняток кинутий від іншого токену (не того, що у Task), стан буде Faulted:

Розрізнення Canceled і Faulted важливе для коду, що аналізує стан завдань після їх завершення — наприклад, при побудові retry-логіки або логування помилок.

Розроблено Tomka Yurii · © 2026 ·