【发布时间】:2016-07-06 15:17:56
【问题描述】:
我有一个Task,它查询一个活动目录并用结果填充一个列表。我已经设置了我的任务,以便可以取消它,但是,当调用取消时,任务会继续执行它的工作。我知道任务已被取消,因为它返回并且打算在任务返回时执行的操作正在运行,但查询继续在后台运行,使用内存和处理能力。任务可以重复启动和“取消”,任务的每次迭代都在运行和使用资源。如何使取消实际取消?
视图模型
private async Task RunQuery(QueryType queryType,
string selectedItemDistinguishedName = null)
{
StartTask();
try
{
_activeDirectoryQuery = new ActiveDirectoryQuery(queryType,
CurrentScope, selectedItemDistinguishedName);
await _activeDirectoryQuery.Execute();
Data = _activeDirectoryQuery.Data.ToDataTable().AsDataView();
CurrentQueryType = queryType;
}
catch (ArgumentNullException)
{
ShowMessage(
"No results of desired type found in selected context.");
}
catch (OutOfMemoryException)
{
ShowMessage("The selected query is too large to run.");
}
FinishTask();
}
private void CancelCommandExecute()
{
_activeDirectoryQuery?.Cancel();
}
ActiveDirectoryQuery
public async Task Execute()
{
_cancellationTokenSource = new CancellationTokenSource();
var taskCompletionSource = new TaskCompletionSource<object>();
_cancellationTokenSource.Token.Register(
() => taskCompletionSource.TrySetCanceled());
DataPreparer dataPreparer = null;
var task = Task.Run(() =>
{
if (QueryTypeIsOu())
{
dataPreparer = SetUpOuDataPreparer();
}
else if (QueryTypeIsContextComputer())
{
dataPreparer = SetUpComputerDataPreparer();
}
else if (QueryTypeIsContextDirectReportOrUser())
{
dataPreparer = SetUpDirectReportOrUserDataPreparer();
}
else if (QueryTypeIsContextGroup())
{
dataPreparer = SetUpGroupDataPreparer();
}
Data = GetData(dataPreparer);
},
_cancellationTokenSource.Token);
await Task.WhenAny(task, taskCompletionSource.Task);
}
public void Cancel()
{
_cancellationTokenSource?.Cancel();
}
Cancel() 由绑定到Button 的Command 调用。该任务可能需要几分钟才能执行,并且可能会消耗数百兆字节的 RAM。如果有帮助,我可以提供任何引用的方法或任何其他信息。
【问题讨论】:
-
您需要在任务中查询token的
IsCancellationRequested属性,并相应地从任务中返回。Cancel不只是“杀死”任务,它只是将该属性的值设置为 true。 -
@KDecker 我假设你的意思是我需要重复查询它?考虑到实际工作做了几个更深的方法,这是不切实际的,但我的设计可能是那里的真正问题。
-
@MichaelBrandonMorris 是的,您需要对其进行测试。也可以使用
ThrowIfCancellationRequested()也可以查看How to: Cancel a Task and Its Children -
@ConradFrix 因此,任务调用方法(见上文),每个方法调用一个静态方法,该方法可能调用其他静态方法。无论如何,首当其冲的工作发生在最深层,最深层需要返回一个对象。如何在允许返回的对象向上传播的同时沿树传播取消?
-
@MichaelBrandonMorris 取消标记与其他任何变量一样。使变量可用于静态方法的方法是相同的。通常这意味着将令牌传递给每个方法。