Я столкнулся с проблемой, как правильно отменить асинхронную задачу.
Вот черновик.
Моя точка входа выполняет две асинхронные задачи. Первая задача выполняет «долгую» работу, а вторая ее отменяет.
Точка входа:
private static void Main()
{
var ctc = new CancellationTokenSource();
var cancellable = ExecuteLongCancellableMethod(ctc.Token);
var cancelationTask = Task.Run(() =>
{
Thread.Sleep(2000);
Console.WriteLine("[Before cancellation]");
ctc.Cancel();
});
try
{
Task.WaitAll(cancellable, cancelationTask);
}
catch (Exception e)
{
Console.WriteLine($"An exception occurred with type {e.GetType().Name}");
}
}
Метод, возвращающий задачу, которую можно отменить:
private static Task ExecuteLongCancellableMethod(CancellationToken token)
{
return Task.Run(() =>
{
token.ThrowIfCancellationRequested();
Console.WriteLine("1st");
Thread.Sleep(1000);
Console.WriteLine("2nd");
Thread.Sleep(1000);
Console.WriteLine("3rd");
Thread.Sleep(1000);
Console.WriteLine("4th");
Thread.Sleep(1000);
Console.WriteLine("[Completed]");
}, token);
}
Моя цель - перестать писать «1-й», «2-й», «3-й» сразу после вызова отмены. Но я получаю следующие результаты:
1st
2nd
3rd
[Before cancellation]
4th
[Completed]
По очевидной причине у меня не было исключения, которое выдает при запросе отмены. Поэтому я попытался переписать метод следующим образом:
private static Task ExecuteLongCancellableAdvancedMethod(CancellationToken token)
{
return Task.Run(() =>
{
var actions = new List<Action>
{
() => Console.WriteLine("1st"),
() => Console.WriteLine("2nd"),
() => Console.WriteLine("3rd"),
() => Console.WriteLine("4th"),
() => Console.WriteLine("[Completed]")
};
foreach (var action in actions)
{
token.ThrowIfCancellationRequested();
action.Invoke();
Thread.Sleep(1000);
}
}, token);
}
И теперь я получил то, что хочу:
1st
2nd
[Before cancellation]
3rd
An exception occurred with type AggregateException
Но я полагаю, что создание коллекции делегатов Action и их выполнение в цикле - не самый удобный способ решения моей проблемы.
Итак, как это правильно делать? И зачем мне передавать свой токен отмены в метод Task.Run в качестве второго аргумента?
Task.Run
вообще не будет запускать делегат - person Jakub Dąbek   schedule 29.08.2017token.ThrowIfCancellationRequested();
в каждом месте, где вы хотите, чтобы выполнение действительно могло быть отменено. Итак, в вашем первом примере перед каждымConsole.WriteLine
. - person Bradley Uffner   schedule 29.08.2017