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

Можно ли принудительно завершить асинхронную операцию?

1.8 Middle🔥 251 комментариев
#C# и ООП#Асинхронность и многопоточность

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

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

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

Короче: да, но осторожно

Да, принудительно завершить асинхронную операцию в Unity можно, но с важными оговорками. Это как остановить поезд на полном ходу — если не знать правильный способ, можно все разнести вдребезги.

Основные подходы к отмене асинхронных операций

1. CancellationToken для Task-based асинхронности

С появлением async/await в C# наиболее корректный способ — использование CancellationTokenSource и CancellationToken.

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

public class AsyncOperationController : MonoBehaviour
{
    private CancellationTokenSource _cancellationTokenSource;
    
    async void Start()
    {
        _cancellationTokenSource = new CancellationTokenSource();
        var token = _cancellationTokenSource.Token;
        
        try
        {
            await LongRunningOperationAsync(token);
        }
        catch (OperationCanceledException)
        {
            Debug.Log("Операция была отменена");
        }
    }
    
    private async Task LongRunningOperationAsync(CancellationToken token)
    {
        for (int i = 0; i < 100; i++)
        {
            // Проверяем токен перед каждой итерацией
            token.ThrowIfCancellationRequested();
            
            await Task.Delay(1000, token);
            Debug.Log($"Шаг {i} выполнен");
        }
    }
    
    private void OnDestroy()
    {
        // Отменяем при уничтожении объекта
        _cancellationTokenSource?.Cancel();
        _cancellationTokenSource?.Dispose();
    }
    
    // Метод для ручной отмены из UI
    public void CancelOperation()
    {
        _cancellationTokenSource?.Cancel();
    }
}

2. Отмена Unity Coroutine

Для корутин Unity есть несколько подходов:

using System.Collections;
using UnityEngine;

public class CoroutineController : MonoBehaviour
{
    private Coroutine _activeCoroutine;
    
    void Start()
    {
        _activeCoroutine = StartCoroutine(LongRunningCoroutine());
    }
    
    IEnumerator LongRunningCoroutine()
    {
        while (true)
        {
            // Проверяем флаг отмены
            if (_shouldStop) yield break;
            
            Debug.Log("Корутин работает...");
            yield return new WaitForSeconds(1f);
        }
    }
    
    private bool _shouldStop = false;
    
    public void StopCoroutineSafely()
    {
        // Способ 1: Установка флага
        _shouldStop = true;
        
        // Способ 2: Остановка по ссылке
        if (_activeCoroutine != null)
        {
            StopCoroutine(_activeCoroutine);
            _activeCoroutine = null;
        }
    }
}

3. Resource.UnloadUnusedAssets() и Resources.UnloadAsset()

Для операций с ресурсами можно принудительно выгрузить неиспользуемые ассеты:

// Принудительная выгрузка ресурсов
Resources.UnloadUnusedAssets();

// Выгрузка конкретного ассета
Resources.UnloadAsset(specificAsset);

Критические предупреждения и лучшие практики

❌ Что НЕЛЬЗЯ делать:

  • Прерывать поток UnityThread.Abort() опасен и устарел
  • Игнорировать исключения при отмене операций
  • Забывать освобождать ресурсыCancellationTokenSource.Dispose() обязателен
  • Прерывать операции в середине критической секции данных

✅ Что НУЖНО делать:

  • Всегда реализовывать graceful shutdown — давать операции завершиться корректно
  • Использовать токены отмены для задач на основе Task
  • Регулярно проверять флаги завершения в циклах корутин
  • Очищать подписки на события при отмене операций
  • Логировать факты отмены для отладки
// Правильный паттерн с использованием using
public async Task ProcessWithTimeoutAsync(int timeoutMs)
{
    using (var cts = new CancellationTokenSource(timeoutMs))
    {
        try
        {
            await ProcessDataAsync(cts.Token);
        }
        catch (TaskCanceledException)
        {
            Debug.LogWarning($"Операция отменена по таймауту: {timeoutMs}ms");
            // Выполнить очистку ресурсов
            CleanupResources();
        }
    }
}

Сравнение подходов

МетодКогда использоватьПреимуществаРиски
CancellationTokenModern async/awaitБезопасность, стандартный C#, таймаутыТребует обработки исключений
StopCoroutine()Unity корутиныИнтеграция с Unity, простотаМожет оставить состояние некорректным
Manual флагиПростые циклыПолный контроль, простотаЛегко пропустить проверку флага

Золотое правило асинхронности в Unity

Всегда проектируйте асинхронные операции с учетом возможности их отмены с самого начала. Добавление механизмов отмены постфактум — это рецепт для багов и утечек ресурсов.

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

Можно ли принудительно завершить асинхронную операцию? | PrepBro