CancellationToken в C#
CancellationToken являются частью механизма отмены асинхронных операций. Например пользователь сидит на сайте и делает запрос на какой-то сложный ресурс. Не дожидаясь ответа он закрывает вкладку браузера, который в свою очередь отменяет запрос. Но наш код не знает что запрос отменен и можно не делать лишнюю работу. А теперь представим что пользователь заходит на сайт и 5 раз перегружает страницу, теперь сервер 5 раз выполняет одну и ту же работу.
Чтобы решить эту проблему нужно использовать механизм отмены задач. Состоит он из двух компонентов:
- CancellationTokenSource — позволяет создавать специальные токены, который содержат информацию про состояние текущей отмены.
- CancellationToken — собственно сам токен, у него есть свойство IsCancellationRequested, которое показывает состояние отмены, а также есть метод, который выбрасывает исключение (OperationCanceledException) в случае отмены операции.
Как это работает?
Большенство методов стандартной библиотеки уже имеют перегрузку, которая принимает токен. Чтобы его создать, нужно сначала создать фабрику CancellationTokenSource. Дальше с ее помощью сгенерировать токен и передать его в качестве аргумента в наш асинхронный метод.
Чтобы отменить задачу нужно вызвать метод Cancel у экземпляра CancellationTokenSource. Он переведет все выпущенные токены в отмененное состояние. Внутри асинхронного метода сработает проверка токена и работа будет завершена.
Также CancellationTokenSource позволяет установить таймаут по истечению которого автоматически отменяться все токены.
Простой пример реализации метода, который принимает токен и проверяет его состояние.
public static void Main()
{
CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
CancellationToken token = cancelTokenSource.Token;
var task = Task.Run(() => Task(cancelTokenSource.Token), cancelTokenSource.Token);
cancelTokenSource.Cancel();
}
public static void Task(CancellationToken cancellationToken)
{
while (true)
{
// делает полезную работу.
cancellationToken.ThrowIfCancellationRequested();
}
}Советы
- В ASP.NET Core приложениях стоит использовать токены отмены для эндпоинтов, которые долго выполняются или сильно нагружают систему. Это позволит отменять такие операции в случае тайм-аутов или когда закрылось подключение.
- Если операция может быть отменена сразу же без дополнительных действий то для проверки отмены стоит использовать ThrowIfCancellationRequested. Если же нам нужно после вызова отмены сделать некую дополнительную работу (очистить ресурсы), то стоит проверять состояние с помощью свойства IsCancellationRequested и если оно равно true — выполнить дополнительную логику очистки.
- Если метод уже выполнил свою работу и была вызвана отмена, то не нужно бросать исключение OperationCanceledException. Нужно просто вернуть результат работы и пускай вызывающий код решать что делать с этим результатом.
- Можно вообще обойтись без использования механизма отмены если код отрабатывает очень быстро.
Полезные ссылки по теме: