← Назад к вопросам

Как отменить Task?

1.8 Middle🔥 232 комментариев
#Асинхронность и многопоточность#Основы C# и .NET

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как отменить Task в C#?

Отмена задач (Task) в C# — это важный механизм для управления долго выполняющимися операциями и предотвращения утечек ресурсов. Для этого используется паттерн Cooperative Cancellation, основанный на структуре CancellationToken.

Основные компоненты отмены

  • CancellationTokenSource: источник токена, который управляет отменой. Он создаёт токены и сигнализирует о отмене.
  • CancellationToken: сам токен, который передаётся в Task или метод. Он только проверяет состояние отмены.
  • Метод Cancel(): вызывает отмену на источнике (CancellationTokenSource.Cancel()).
  • Проверка IsCancellationRequested: задача должна периодически проверять токен на отмену и корректно завершаться.

Базовый пример отмены задачи

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        // 1. Создаём источник токена
        var cts = new CancellationTokenSource();
        CancellationToken token = cts.Token;

        // 2. Запускаем задачу, передавая токен
        Task longRunningTask = Task.Run(() =>
        {
            for (int i = 0; i < 10; i++)
            {
                // 3. Проверяем запрос на отмену
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine("Операция прервана.");
                    return; // Корректно завершаем метод
                }

                Console.WriteLine($"Шаг {i}");
                Thread.Sleep(1000); // Имитация работы
            }
        }, token);

        // 4. Имитируем внешнюю отмену после 3 секунд
        await Task.Delay(3000);
        cts.Cancel(); // Сигнализируем об отмене

        try
        {
            await longRunningTask; // Ожидаем завершения задачи
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("Task была отменена через исключение.");
        }
    }
}

Обработка отмены в асинхронных методах и внешних API

Для методов, которые поддерживают токен отмены (например, многие в System.Threading.Tasks или HttpClient), токен передаётся как аргумент.

// Пример с HttpClient
using var client = new HttpClient();
cts.CancelAfter(2000); // Автоматическая отмены через 2 секунды
try
{
    var response = await client.GetAsync("https://example.com", token);
}
catch (OperationCanceledException)
{
    Console.WriteLine("Загрузка была отменена.");
}

// Пример с Task.Delay
await Task.Delay(5000, token); // Delay также поддерживает CancellationToken

Использование ThrowIfCancellationRequested

Внутри задачи можно не проверять IsCancellationRequested вручную, а использовать метод ThrowIfCancellationRequested(), который автоматически выбрасывает OperationCanceledException, если отмена запрошена.

Task.Run(() =>
{
    for (int i = 0; i < 10; i++)
    {
        token.ThrowIfCancellationRequested(); // Проверка и исключение
        Console.WriteLine($"Шаг {i}");
        Thread.Sleep(1000);
    }
}, token);

При ожидании такой задачи (await) исключение OperationCanceledException будет перехвачено, что явно указывает на причину остановки.

Связывание нескольких токенов (Linked CancellationTokenSource)

Часто требуется создать токен, который отменяется при отмене одного из нескольких источников. Для этого используется CancellationTokenSource.CreateLinkedTokenSource.

var cts1 = new CancellationTokenSource();
var cts2 = new CancellationTokenSource();
var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token);

var task = Task.Run(() =>
{
    linkedCts.Token.ThrowIfCancellationRequested();
    // Работа задачи...
}, linkedCts.Token);

// Отмена через любой из исходных источников приведёт к отмене задачи
cts1.Cancel(); // Теперь задача также будет отменена

Автоматическая отмена через CancelAfter

CancellationTokenSource имеет метод CancelAfter, который автоматически вызывает отмену после заданного времени.

var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(5)); // Автоотмена через 5 секунд

Отмена нескольких задач одним токеном

Один CancellationTokenSource может управлять отменой многих задач.

var cts = new CancellationTokenSource();
CancellationToken token = cts.Token;

List<Task> tasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
    tasks.Add(Task.Run(() => DoWork(token), token));
}

// Отмена всех задач
cts.Cancel();
await Task.WhenAll(tasks); // Ожидаем завершения всех задач (в состоянии Canceled)

Итог и ключевые выводы

  • Отмена Task в C# является кооперативной: задача должна сама проверять токен и корректно реагировать на запрос отмены.
  • CancellationTokenSource — это управляющий объект, CancellationToken — это только маркер состояния.
  • Для обработки отмены используйте либо проверку IsCancellationRequested, либо ThrowIfCancellationRequested() с перехватом OperationCanceledException.
  • Токены отмены поддерживаются многими стандартными API (HttpClient, Task.Delay, etc.) для единообразного управления.
  • Используйте LinkedTokenSource для сложных сценариев зависимости от нескольких источников отмены и CancelAfter для автоматической отмены по времени.

Отмена задач — это не просто вызов метода, а целая архитектура, которая требует внимательной интеграции в код задачи для обеспечения безопасного и контролируемого завершения работы.

Как отменить Task? | PrepBro