只需要’最近’的任务 – 取消/忽略的最佳做法?

我有一个看起来像这样的任务:

var task = Task.Factory.StartNew (LongMethod); task.ContinueWith(TaskCallback, TaskScheduler.FromCurrentSynchronizationContext()); 

LongMethod调用一个长期运行的服务,在此期间我不能(或者至少不认为我可以),不断轮询取消令牌以查看它是否已被取消。 但是,我有兴趣’取消’或忽略回调方法。

当调用TaskCallback时,我只对’结果’感兴趣, 如果它来自最近的任务(让我们假设LongMethod调用的服务保留了顺序,并且还假设用户可以多次单击该按钮,但只有最新的一个是相关的)。

我已按以下方式修改了我的代码:创建任务后,我将其添加到堆栈顶部。 在TaskCallback中,我检查传递给回调的任务是否是最新的(即堆栈顶部的TryPeek)。 如果不是,我只是忽略了结果。

 private ConcurrentStack _stack = new ConcurrentStack(); private void OnClick(object sender, ItemClickEventArgs e) { var task = Task.Factory.StartNew ( LongMethod); task.ContinueWith(TaskCallback, TaskScheduler.FromCurrentSynchronizationContext()); _stack.Push(task); } private void TaskCallback(Task task) { Task topOfStack; if(_stack.TryPeek(out topOfStack)) //not the most recent { if (task != topOfStack) return; } //else update UI } 

我很确定这不是“最佳实践”解决方案。 但是什么呢? 传递和维护取消令牌也不是那么优雅。

我个人觉得以下方法是最优雅的:

 // Cancellation token for the latest task. private CancellationTokenSource cancellationTokenSource; private void OnClick(object sender, ItemClickEventArgs e) { // If a cancellation token already exists (for a previous task), // cancel it. if (this.cancellationTokenSource != null) this.cancellationTokenSource.Cancel(); // Create a new cancellation token for the new task. this.cancellationTokenSource = new CancellationTokenSource(); CancellationToken cancellationToken = this.cancellationTokenSource.Token; // Start the new task. var task = Task.Factory.StartNew(LongMethod, cancellationToken); // Set the task continuation to execute on UI thread, // but only if the associated cancellation token // has not been cancelled. task.ContinueWith(TaskCallback, cancellationToken, TaskContinuationOptions.NotOnCanceled, TaskScheduler.FromCurrentSynchronizationContext()); } private void TaskCallback(Task task) { // Just update UI } 

我知道您无法取消长时间运行的任务,但希望在取消时从用户的角度立即中止该过程。

与长时间运行的任务并行启动取消任务。 继续关闭Task.WhenAny(longRunningTask, cancelTask)并检查完成的任务是否是长时间运行的任务或取消任务。 然后,您可以决定要执行的操作(显示结果或更新UI)。

当您取消“取消任务”时,继续将立即触发。