Ответ
CancellationToken — это структура в .NET, предназначенная для безопасной и кооперативной отмены долго выполняющихся или асинхронных операций. Он позволяет передать в метод сигнал о запросе на отмену, а методу — периодически проверять этот сигнал и корректно завершать работу.
Основные компоненты:
CancellationTokenSource: Источник токена. Управляет состоянием отмены через методCancel().CancellationToken: Легковесная структура, которая только отражает состояние отмены. Передается в отменяемые методы.
Базовый пример использования:
public async Task ProcessDataAsync(CancellationToken cancellationToken)
{
// 1. Периодическая ручная проверка
for (int i = 0; i < 100; i++)
{
cancellationToken.ThrowIfCancellationRequested(); // Выбросит OperationCanceledException
// ... выполнение работы на шаге i ...
await Task.Delay(100, cancellationToken); // 2. Автоматическая проверка в поддерживающих API
}
}
// Использование
public async Task MainMethod()
{
using var cts = new CancellationTokenSource();
// Запланировать отмену через 5 секунд, например, по таймауту
cts.CancelAfter(TimeSpan.FromSeconds(5));
try
{
await ProcessDataAsync(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Операция была отменена.");
}
}
Продвинутые сценарии:
- Объединение токенов: Полезно, когда операция должна реагировать на несколько источников отмены (например, пользовательский запрос + общий таймаут приложения).
var userCancellation = new CancellationTokenSource(); var timeoutCancellation = new CancellationTokenSource(TimeSpan.FromSeconds(30));
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource( userCancellation.Token, timeoutCancellation.Token );
await ProcessDataAsync(linkedCts.Token);
* **Регистрация callback при отмене:**
```csharp
cancellationToken.Register(() =>
{
Console.WriteLine("Токен отменен, выполняется очистка...");
// Освобождение неуправляемых ресурсов и т.д.
});
Важные принципы:
- Отмена является кооперативной. Метод должен сам проверять токен и корректно завершаться.
- После вызова
Cancel()соответствующийCancellationTokenпереходит в состояние "отменен" и больше не может быть использован заново. - Многие API .NET (например,
Task.Delay,HttpClient.SendAsync, EF CoreToListAsync) имеют перегрузки, принимающиеCancellationToken.
Ответ 18+ 🔞
Смотри, вот эта штука — CancellationToken — это типа такой вежливый, но настойчивый способ сказать какому-нибудь долбаному методу: «Эй, дружок, сворачивай лавочку, нам тут уже не надо».
Представь, ты запустил на компе архивацию терабайта фоток своей собаки, а потом передумал. Ну кнопки же «Отмена» нет, приходится процесс убивать через диспетчер. Так вот, CancellationToken — это и есть цивилизованная кнопка «Отмена» внутри твоего кода.
Из чего это говно состоит, прости Господи:
CancellationTokenSource— это начальник, который орет «Отменить!». У него есть кнопкаCancel().CancellationToken— это бумажка, которую начальник дает рабочим (твоим методам). Рабочие смотрят на бумажку и видят, не написал ли начальник на ней «ВСЁ, ПИЗДЕЦ, ХВАТИТ».
Простой пример, чтоб было понятно даже мне вчерашнему:
public async Task КачаюМемыБесконечноAsync(CancellationToken cancellationToken)
{
// 1. Рабочий (метод) время от времени смотрит на бумажку
for (int i = 0; i < 1000000; i++)
{
cancellationToken.ThrowIfCancellationRequested(); // Если на бумажке "ПИЗДЕЦ" — выкидывает исключение и сваливает
// ... тут он реально качает мемы ...
await Task.Delay(100, cancellationToken); // 2. Или бумажку можно дать другому API, оно само проверит
}
}
// А вот как этим пользоваться
public async Task MainMethod()
{
using var cts = new CancellationTokenSource(); // Создаём начальника
// Говорим ему: «Через 5 секунд накричи "ПИЗДЕЦ"»
cts.CancelAfter(TimeSpan.FromSeconds(5));
try
{
await КачаюМемыБесконечноAsync(cts.Token); // Даём рабочиму бумажку от этого начальника
}
catch (OperationCanceledException) // Ловим крик начальника в виде исключения
{
Console.WriteLine("Ну я отменил, чё бубнить-то.");
}
}
А бывает и посложнее, вот смотри:
- Токены-близнецы: Когда твоему рабочему нужно слушать сразу двух начальников (например, юзера и системный таймаут).
var userCts = new CancellationTokenSource(); // Юзер может нажать крестик var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(30)); // Система не будет ждать дольше 30 сек
// Скрепляем их бумажки в одну супер-бумажку using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource( userCts.Token, timeoutCts.Token );
await КачаюМемыБесконечноAsync(linkedCts.Token); // Рабочий слушает обоих // Достаточно одному начальнику орануть — и в супер-бумажке тоже будет "ПИЗДЕЦ"
* **Колбэк на отмену:** Это типа когда рабочий, увидев «ПИЗДЕЦ» на бумажке, перед тем как свалить, должен всё же выключить свет и закрыть дверь.
```csharp
cancellationToken.Register(() =>
{
Console.WriteLine("Ладно, отменяюсь, но сперва сохраню черновик...");
// Тут срочная очистка, освобождение файлов и т.д.
});
Главное, что надо запомнить:
- Отмена — добровольная. Если рабочий-метод упёртый мудак и не смотрит на бумажку (
cancellationToken), то он будет работать, пока комп не выключится. Это кооперативная система, а не приказ расстрелять процесс. - Крикнув «ПИЗДЕЦ» один раз (
Cancel()), начальник охрипнет навсегда. Токен нельзя использовать заново. - Всякие современные штуки в .NET (
Task.Delay,HttpClient, EF Core) — они хорошие, воспитанные ребята. Если дать им эту бумажку, они сами будут её проверять и аккуратно прекращать работу.