Отмена. Часть 2: Запрос Отмены.
В прошлый раз мы рассмотрели базовый контракт отмены. Теперь рассмотрим, как создавать токены отмены для запроса отмены.
CancellationTokenSource
Некоторые токены отмены предоставляются используемой вами платформой или библиотекой. Например, ASP.NET предоставит вам CancellationToken, который представляет собой неожиданное отключение клиента. Polly может предоставить вашему делегату токен, который представляет собой более общую отмену (например, срабатывание политики тайм-аута).
В других сценариях вам потребуется предоставить собственный токен. В общем случае, когда вы хотите создать CancellationToken, который можно будет отменить позже, нужно использовать CancellationTokenSource.
Каждый CancellationTokenSource управляет своим набором токенов. Каждый токен, созданный из CancellationTokenSource, представляет собой небольшую структуру, которая ссылается на свой CancellationTokenSource. Токен отмены может только отвечать на запросы отмены; CancellationTokenSource необходим для запроса отмены. Поэтому запрашивающий код создает CancellationTokenSource и сохраняет ссылку на него (используя эту ссылку позже для запроса отмены), а отвечающий код просто получает CancellationToken и использует его для ответа на запросы отмены.
Таймауты
Одной из распространённых потребностей отмены является реализация тайм-аута. Решение состоит в том, чтобы иметь таймер, который запрашивает отмену по истечении срока его действия. В CancellationTokenSource такое поведение встроено. Вы можете использовать конструктор CancellationTokenSource, который принимает таймаут, или вызвать CancelAfter для существующего CancellationTokenSource:
async Task DoSomethingWithTimeoutAsync()
{
// Создаём CTS, который отменится через 5 минут
using CancellationTokenSource cts
= new(TimeSpan.FromMinutes(5));
// Передаём токен
await DoSomethingAsync(cts.Token);
// В конце метода CTS уничтожается
// Его токены не могут больше использоваться
}
Очистка
Чтобы избежать утечек ресурсов, важно уничтожать (dispose) экземпляры CancellationTokenSource. Очищается несколько видов ресурсов: во-первых, таймер тайм-аута (если он есть); во-вторых, все «слушатели», прикрепленные к токенам отмены. Эта очистка выполняется при отмене или уничтожении CancellationTokenSource. Вы должны убедиться, что либо одно, либо другое выполнено, чтобы избежать утечек ресурсов.
Если токен отмены сохраняется и используется позже, вы бы не хотели уничтожать CancellationTokenSource. В этом случае следует сохранять CancellationTokenSource активным до тех пор, пока вы не будете уверены, что весь код, использующий его токены, выполнен. Это более сложный случай, и иногда удобнее отменить CancellationTokenSource, а не уничтожать его.
Предупреждение: уничтожение связанных источников CancellationTokenSource.
Вызов Cancel или Dispose очистит все регистрации для конкретного CancellationTokenSource. Однако если этот CancellationTokenSource связан с «родительским» CancellationTokenSource, вызов Cancel для «дочернего» CancellationTokenSource приведёт к отмене регистрации в «родительском» CancellationTokenSource. Вы можете вызвать Dispose (или использовать оператор using) для «дочернего элемента», чтобы очистить регистрацию у родителя этого дочернего элемента, разрывая ссылку.
Эта и другие темы, касающиеся связанных CancellationTokenSource, будут рассмотрены далее в этой серии.
Источник: https://blog.stephencleary.com/2022/03/cancellation-2-requesting-cancellation.html