我有一个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();
}
Run Code Online (Sandbox Code Playgroud)
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();
}
Run Code Online (Sandbox Code Playgroud)
Cancel()由绑定Command到 a 的 a 调用Button。该任务可能需要几分钟才能执行,并且可能消耗数百兆的 RAM。如果有帮助,我可以提供任何引用的方法或任何其他信息。
取消是合作性的,如果你想要取消操作,你需要编辑你的函数来取消。所以执行会变成
public async Task Execute()
{
_cancellationTokenSource = new CancellationTokenSource();
var taskCompletionSource = new TaskCompletionSource<object>();
//Token registrations need to be disposed when done.
using(_cancellationTokenSource.Token.Register(
() => taskCompletionSource.TrySetCanceled()))
{
DataPreparer dataPreparer = null;
var task = Task.Run(() =>
{
if (QueryTypeIsOu())
{
dataPreparer = SetUpOuDataPreparer(_cancellationTokenSource.Token);
}
else if (QueryTypeIsContextComputer())
{
dataPreparer = SetUpComputerDataPreparer(_cancellationTokenSource.Token);
}
else if (QueryTypeIsContextDirectReportOrUser())
{
dataPreparer = SetUpDirectReportOrUserDataPreparer(_cancellationTokenSource.Token);
}
else if (QueryTypeIsContextGroup())
{
dataPreparer = SetUpGroupDataPreparer(_cancellationTokenSource.Token);
}
Data = GetData(dataPreparer, _cancellationTokenSource.Token);
},
_cancellationTokenSource.Token);
await Task.WhenAny(task, taskCompletionSource.Task);
}
}
Run Code Online (Sandbox Code Playgroud)
然后从这些方法内部。如果这些函数中有循环,则需要token.ThrowIfCancellationRequested()从循环内部调用。如果您不循环并且调用某些外部 API,则需要使用该 API 的取消方法,希望该 API 能够接受CancellationToken,如果不接受,则需要使用像 中那样的.Cancel()方法来调用方法。RegisterExecute
如果 API 没有公开取消查询的方法,则提前停止查询的唯一安全方法是您需要将查询移至单独的 exe。当您执行查询时,您将执行 avar proc = Process.Start(...)来启动 exe。要与其进行通信,请使用某种形式的 IPC(例如WCF over Named Pipes ),您可以Guid在进程启动之前生成 并将其作为参数传递,然后使用该 guid 作为命名管道的名称。如果您需要提前结束查询,您可以执行 aproc.Kill()来结束外部进程。
| 归档时间: |
|
| 查看次数: |
2169 次 |
| 最近记录: |