Какие знаешь способы отмены задачи?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Способы отмены задач в C#
В C# существует несколько механизмов отмены асинхронных и длительных операций, которые позволяют корректно прерывать выполнение задач. Основные подходы основаны на использовании CancellationToken и связанных с ним конструкциях.
1. Использование CancellationTokenSource и CancellationToken
Это основной и наиболее рекомендуемый способ. CancellationTokenSource генерирует токены отмены, которые передаются в методы, поддерживающие отмену.
using System;
using System.Threading;
using System.Threading.Tasks;
public class CancellationExample
{
public static async Task ProcessWithCancellationAsync()
{
// Создаем источник токена отмены
var cts = new CancellationTokenSource();
// Запускаем фоновую задачу для отмены через 3 секунды
_ = Task.Delay(3000).ContinueWith(_ =>
{
cts.Cancel();
Console.WriteLine("Cancellation requested");
});
try
{
await LongRunningOperationAsync(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation was cancelled");
}
}
private static async Task LongRunningOperationAsync(CancellationToken token)
{
for (int i = 0; i < 100; i++)
{
// Проверяем, не запрошена ли отмена
token.ThrowIfCancellationRequested();
await Task.Delay(100, token);
Console.WriteLine($"Processing item {i}");
}
}
}
2. Связывание нескольких источников отмены
Можно объединять несколько токенов отмены, используя CancellationTokenSource.CreateLinkedTokenSource().
public static async Task LinkedCancellationAsync(
CancellationToken externalToken1,
CancellationToken externalToken2)
{
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(
externalToken1, externalToken2);
try
{
await ProcessDataAsync(linkedCts.Token);
}
catch (OperationCanceledException ex)
{
// Определяем, какой токен вызвал отмену
if (externalToken1.IsCancellationRequested)
Console.WriteLine("Cancelled by first token");
else if (externalToken2.IsCancellationRequested)
Console.WriteLine("Cancelled by second token");
}
}
3. Отмена с таймаутом
CancellationTokenSource поддерживает автоматическую отмену через заданное время.
public static async Task ProcessWithTimeoutAsync()
{
// Токен автоматически отменится через 5 секунд
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
try
{
await DownloadLargeFileAsync(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Download cancelled due to timeout");
}
}
4. Отмена через регистрацию колбэков
Можно зарегистрировать callback-функции, которые выполнятся при отмене операции.
public static Task ProcessWithCallbacksAsync(CancellationToken token)
{
var tcs = new TaskCompletionSource<bool>();
// Регистрируем колбэк для очистки ресурсов
token.Register(() =>
{
CleanupResources();
tcs.TrySetCanceled(token);
});
return ProcessOperationAsync(token, tcs);
}
5. Ручная проверка CancellationToken в циклах
Для операций без встроенной поддержки async/await.
public static void ProcessSynchronously(CancellationToken token)
{
for (int i = 0; i < 1000000; i++)
{
if (token.IsCancellationRequested)
{
// Выполняем корректное завершение
Cleanup();
return; // или throw new OperationCanceledException();
}
// Выполняем работу
ProcessItem(i);
}
}
6. Использование метода CancelAfter()
Динамическая установка таймаута для уже созданного CancellationTokenSource.
public static async Task DynamicCancellationAsync()
{
var cts = new CancellationTokenSource();
// Устанавливаем таймаут после начала операции
cts.CancelAfter(TimeSpan.FromSeconds(10));
await ExecuteWithDynamicTimeoutAsync(cts.Token);
}
7. Отмена через CancellationToken в методах Task
Многие методы Task имеют перегрузки с поддержкой CancellationToken.
public static async Task TaskWithCancellationAsync()
{
var cts = new CancellationTokenSource();
// Task.Delay с поддержкой отмены
try
{
await Task.Delay(TimeSpan.FromSeconds(10), cts.Token);
}
catch (TaskCanceledException)
{
Console.WriteLine("Task.Delay was cancelled");
}
// Task.Run с поддержкой отмены
var task = Task.Run(() =>
{
// Работа, которую можно отменить
}, cts.Token);
}
8. Создание собственных отменяемых операций
При разработке библиотек следует правильно реализовывать поддержку отмены.
public class CustomCancellableOperation
{
public async Task<int> ComputeAsync(
CancellationToken cancellationToken = default)
{
await Task.Yield();
// Регулярно проверяем токен
for (int i = 0; i < 100; i++)
{
cancellationToken.ThrowIfCancellationRequested();
// Передаем токен в глубинные вызовы
await StepAsync(i, cancellationToken);
}
return 42;
}
}
Рекомендации по использованию
- Всегда передавайте CancellationToken в асинхронные методы, если они поддерживают длительные операции
- Используйте ThrowIfCancellationRequested() для быстрой проверки отмены
- Корректно обрабатывайте OperationCanceledException на верхних уровнях
- Освобождайте ресурсы в блоках finally или через using
- Избегайте использования Thread.Abort() - это устаревший и опасный подход
- Предоставляйте параметр по умолчанию в публичных API:
CancellationToken cancellationToken = default
Правильная обработка отмены задач критически важна для создания отзывчивых и надежных приложений, особенно в серверных сценариях, где необходимо управлять временем выполнения операций и ресурсами.