我的任务看起来像这样:
var task = Task.Factory.StartNew <object>(LongMethod);
task.ContinueWith(TaskCallback, TaskScheduler.FromCurrentSynchronizationContext());
LongMethod调用一个长时间运行的服务,在此期间我不能(或者至少不认为我可以),不断轮询取消令牌以查看它是否已被取消。但是,我对'取消'或忽略回调方法很感兴趣。
当调用TaskCallback时,我只对“结果”感兴趣,如果它来自最近的任务(让我们假设LongMethod调用的服务保留了顺序,并且还假设用户可以多次单击该按钮,但只有最新的按钮是相关的。)
我已按以下方式修改了我的代码:创建任务后,我将其添加到堆栈的顶部。在TaskCallback中,我检查传递给回调的任务是否是最新的任务(即堆栈顶部的TryPeek)。如果不是,我只是忽略了结果。
private ConcurrentStack<Task> _stack = new ConcurrentStack<Task>();
private void OnClick(object sender, ItemClickEventArgs e)
{
var task = Task.Factory.StartNew < object >( LongMethod);
task.ContinueWith(TaskCallback, TaskScheduler.FromCurrentSynchronizationContext());
_stack.Push(task);
}
private void TaskCallback(Task<object> task)
{
Task topOfStack;
if(_stack.TryPeek(out topOfStack)) //not the most recent
{
if (task != topOfStack) return;
}
//else update UI
}
我很确定这不是'最佳实践'解决方案。但是什么呢?传递和维护取消令牌也不是那么优雅。
答案 0 :(得分:5)
我个人认为以下方法是最优雅的:
// 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<object>(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<object> task)
{
// Just update UI
}
答案 1 :(得分:1)
我知道您无法取消长时间运行的任务,但希望在取消时从用户的角度立即中止该过程。
与长时间运行的任务并行启动取消任务。继续关闭Task.WhenAny(longRunningTask, cancelTask)
并检查完成的任务是否为长时间运行的任务或取消任务。然后,您可以决定要执行的操作(显示结果或更新UI)。
当您取消“取消任务”时,继续将立即触发。