如何在等待中取消任务?
我正在玩这些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() { }
阅读取消 (在.NET 4.0中引入,此后基本不变)和基于任务的asynchronous模式 ,该模式提供有关如何在async
方法中使用CancellationToken
指导。
总而言之,将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());
我只想添加到已经接受的答案。 我被困在这,但是我正在处理完整的事件的另一条路线。 而不是等待,我添加一个完成的处理程序的任务。
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; }
有了这条路线,所有的处理都已经完成了,当任务被取消时,它只是触发事件处理程序,你可以看到它是否被取消了。