Как отменить задание в ожидании?
Я играю с этими задачами Windows 8 WinRT, и я пытаюсь отменить задачу, используя метод ниже, и он работает до некоторой степени. Метод CancelNotification действительно вызывается, что заставляет вас думать, что задача была отменена, но в фоновом режиме задача продолжает работать, а затем после ее завершения состояние задачи всегда завершено и никогда не отменяется. Есть ли способ полностью остановить задачу, когда она отменена?
private async void TryTask()
{
CancellationTokenSource source = new CancellationTokenSource();
source.Token.Register(CancelNotification);
source.CancelAfter(TimeSpan.FromSeconds(1));
var task = Task<int>.Factory.StartNew(() => slowFunc(1, 2), source.Token);
await task;
if (task.IsCompleted)
{
MessageDialog md = new MessageDialog(task.Result.ToString());
await md.ShowAsync();
}
else
{
MessageDialog md = new MessageDialog("Uncompleted");
await md.ShowAsync();
}
}
private int slowFunc(int a, int b)
{
string someString = string.Empty;
for (int i = 0; i < 200000; i++)
{
someString += "a";
}
return a + b;
}
private void CancelNotification()
{
}
3 ответа:
Читать далее отмена (который был представлен в .NET 4.0 и в значительной степени не изменился с тех пор) и Асинхронный Шаблон На Основе Задач, который предоставляет рекомендации о том, как использовать
CancellationToken
Сasync
методы.подводя итог, вы передаете
CancellationToken
в каждом методе, который поддерживает отмену, и этот метод должен периодически проверять его.private async Task TryTask() { CancellationTokenSource source = new CancellationTokenSource(); source.CancelAfter(TimeSpan.FromSeconds(1)); Task<int> task = Task.Run(() => slowFunc(1, 2, source.Token), source.Token); // (A canceled task will raise an exception when awaited). await task; } private int slowFunc(int a, int b, CancellationToken cancellationToken) { string someString = string.Empty; for (int i = 0; i < 200000; i++) { someString += "a"; if (i % 1000 == 0) cancellationToken.ThrowIfCancellationRequested(); } return a + b; }
или, чтобы избежать изменения
slowFunc
(допустим у вас нет доступа к исходному коду например):var source = new CancellationTokenSource(); //original code source.Token.Register(CancelNotification); //original code source.CancelAfter(TimeSpan.FromSeconds(1)); //original code var completionSource = new TaskCompletionSource<object>(); //New code source.Token.Register(() => completionSource.TrySetCanceled()); //New code var task = Task<int>.Factory.StartNew(() => slowFunc(1, 2), source.Token); //original code //original code: await task; await Task.WhenAny(task, completionSource.Task); //New code
вы также можете использовать хорошие методы расширения от https://github.com/StephenCleary/AsyncEx и это выглядит так просто, как:
await Task.WhenAny(task, source.Token.AsTask());
Я просто хочу добавить к уже принято отвечать. Я застрял на этом, но я шел другим путем по обработке полного события. Вместо того, чтобы запускать await, я добавляю завершенный обработчик к задаче.
Comments.AsAsyncAction().Completed += new AsyncActionCompletedHandler(CommentLoadComplete);
где обработчик событий выглядит так
private void CommentLoadComplete(IAsyncAction sender, AsyncStatus status ) { if (status == AsyncStatus.Canceled) { return; } CommentsItemsControl.ItemsSource = Comments.Result; CommentScrollViewer.ScrollToVerticalOffset(0); CommentScrollViewer.Visibility = Visibility.Visible; CommentProgressRing.Visibility = Visibility.Collapsed; }
С этим маршрутом вся обработка уже выполнена для вас, когда задача отменена, она просто запускает обработчик событий, и вы можете увидеть, была ли она отменена там.