等待任务取消永久等待
我有一个表单,我在其中启动一个任务来加载内容。如果用户单击取消,则当然需要取消该任务。但似乎我做错了什么。该表单永远不会关闭并持续等待任务:等待任务取消永久等待
public partial class Designer : Form
{
private CancellationTokenSource _cancellationTokenSource;
private Task _loadTask;
private async void Designer_Shown(object sender, EventArgs e)
{
_cancellationTokenSource = new CancellationTokenSource();
try
{
_loadTask= Workbench.Instance.CurrentPackage.LoadObjects(_cancellationTokenSource.Token);
await _loadTask;
}
catch (Exception ex)
{
Debug.Print(ex.ToString());
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
_cancellationTokenSource.Cancel();
_loadTask.Wait(); //Waits forever
this.DialogResult = DialogResult.Cancel;
this.Close();
}
}
我的错在哪里?
编辑 代码LoadObjects()
public Task LoadObjects(CancellationToken cancelToken)
{
return Task.Run(() =>
{
LoadParameters(cancelToken);
LoadConditionChecks(cancelToken);
LoadConditonRules(cancelToken);
LoadOperations(cancelToken);
}, cancelToken);
}
我通过令牌的子方法因为回路实际上是有...
你被击中UI线程死锁等待它并致电Task.Wait()
。不惜一切代价避免Task.Wait
。
服务在一个异步执行的取消,这样的结果:
private async void btnCancel_Click(object sender, EventArgs e)
{
_cancellationTokenSource.Cancel();
await _loadTask;
this.DialogResult = DialogResult.Cancel;
this.Close();
}
这是唯一的时间async void
是可接受的。
我最喜欢的异步代码的人斯蒂芬·克利里提供了一个辉煌的博客文章,解释为什么你应该避免Task.Wait
和Task.Result
作为支撑机制 - Don't Block on Async Code
为了什么它的价值,当我取消,我从来不等待任务完成。我立即回复取消,并让任务在后台完成。这为用户提供了响应式UI体验。如果我需要从已取消的任务中获得结果,我将在用户单击取消后进行一些UI工作以进行通信'等待结束操作'。
这就是它......在我用google找到的所有例子中,他们都做了'.Wait()'事情...... –
您没有使用取消令牌。这种模式称为合作任务取消 - 消费者和执行代码都需要为取消活动提供服务。这有助于您在取消后保持正确的状态。
的解决方案 - 更新LoadX()方法:
void LoadParameters(cancelToken)
{
... // do some work
cancelToken.ThrowIfCancellationRequested();
... // do some more work
}
任务取消需要运行,以检查它是否被取消的任务。这听起来好像不这样做,但我不知道Workbench是什么。 – Equalsk
您是否控制'Workbench.Instance.CurrentPackage.LoadObjects'的代码。你确定它是尊重取消标记吗? – Gusdor
代码中接受'CancellationToken'的地方应该有一个像CancellationToken.IsCancellationRequested或CancellationToken.ThrowIfCancellationRequested这样的取消检查如果它不是只有atb,那么你会得到这个行为 –