如何在 PLINQ 中等待取消令牌注册方法
How to wait for Cancellation Token Register method within a PLINQ
正如您在我下面的代码中看到的那样,为每个 Employee 调用了 ProcessThisEmployee。在该方法中,我在取消操作时调用第三方库的 Clean 方法。
假设 Clean 方法需要相当多的时间。当 ProcessThisEmployee 方法的所有 运行 个实例的 Clean 方法完成时,我想做的是在 UI 中显示一些消息。
这意味着我需要等待所有 Clean 方法完成。现在,我有一个 WaitAll 任务,但我不确定它是否也会等待所有取消完成。有什么想法吗?
class ProcessEmployees
{
private List<Employee> _Employees;
CancellationTokenSource cs = new CancellationTokenSource();
public ProcessEmployees()
{
_Employees = new List<Employee>()
{
new Employee() { ID = 1, FirstName = "John", LastName = "Doe" },
new Employee() { ID = 2, FirstName = "Peter", LastName = "Saul" },
new Employee() { ID = 3, FirstName = "Mike", LastName = "Sue" },
new Employee() { ID = 4, FirstName = "Catherina", LastName = "Desoza" },
new Employee() { ID = 5, FirstName = "Paul", LastName = "Smith" }
};
}
public void StartProcessing()
{
try
{
Task[] tasks = this._Employees.AsParallel().WithCancellation(cs.Token).Select(x => this.ProcessThisEmployee(x, cs.Token)).ToArray();
Task.WaitAll(tasks);
}
catch (AggregateException ae)
{
// error handling code
}
// other stuff
}
private async Task ProcessThisEmployee(Employee x, CancellationToken token)
{
ThirdPartyLibrary library = new ThirdPartyLibrary();
token.ThrowIfCancellationRequested();
using(token.Register(() => library.Clean())
{
await Task.Factory.StartNew(() => library.SomeAPI(x) );
}
}
}
好吧,您可以使用 CountdownEvent
轻松等待所有这些。您在开始时设置它的大小,在每个 library.Clean()
之后发出信号并使用 Wait()
:
等待它达到 0
private CountdownEvent _countdownEvent;
public void Cancel()
{
cs.Cancel();
_countdownEvent.Wait();
// Update UI
}
public void StartProcessing()
{
try
{
_countdownEvent = new CountdownEvent(_Employees.Count);
Task[] tasks = this._Employees.AsParallel().WithCancellation(cs.Token).Select(x => this.ProcessThisEmployee(x, cs.Token)).ToArray();
Task.WaitAll(tasks);
}
catch (AggregateException ae)
{
// error handling code
}
// other stuff
}
private async Task ProcessThisEmployee(Employee x, CancellationToken token)
{
ThirdPartyLibrary library = new ThirdPartyLibrary();
token.ThrowIfCancellationRequested();
using(token.Register(() => { library.Clean(); _countdownEvent.Signal(); })
{
await Task.Factory.StartNew(() => library.SomeAPI(x) );
}
}
但是,您需要意识到,您尝试执行的操作可能很危险,因为您无法控制何时启动取消。如果您的一些员工在 using 块之前或之后并且您取消了操作 library.Clean
将不会被调用,因此您可以永远等待它。
正如您在我下面的代码中看到的那样,为每个 Employee 调用了 ProcessThisEmployee。在该方法中,我在取消操作时调用第三方库的 Clean 方法。 假设 Clean 方法需要相当多的时间。当 ProcessThisEmployee 方法的所有 运行 个实例的 Clean 方法完成时,我想做的是在 UI 中显示一些消息。 这意味着我需要等待所有 Clean 方法完成。现在,我有一个 WaitAll 任务,但我不确定它是否也会等待所有取消完成。有什么想法吗?
class ProcessEmployees
{
private List<Employee> _Employees;
CancellationTokenSource cs = new CancellationTokenSource();
public ProcessEmployees()
{
_Employees = new List<Employee>()
{
new Employee() { ID = 1, FirstName = "John", LastName = "Doe" },
new Employee() { ID = 2, FirstName = "Peter", LastName = "Saul" },
new Employee() { ID = 3, FirstName = "Mike", LastName = "Sue" },
new Employee() { ID = 4, FirstName = "Catherina", LastName = "Desoza" },
new Employee() { ID = 5, FirstName = "Paul", LastName = "Smith" }
};
}
public void StartProcessing()
{
try
{
Task[] tasks = this._Employees.AsParallel().WithCancellation(cs.Token).Select(x => this.ProcessThisEmployee(x, cs.Token)).ToArray();
Task.WaitAll(tasks);
}
catch (AggregateException ae)
{
// error handling code
}
// other stuff
}
private async Task ProcessThisEmployee(Employee x, CancellationToken token)
{
ThirdPartyLibrary library = new ThirdPartyLibrary();
token.ThrowIfCancellationRequested();
using(token.Register(() => library.Clean())
{
await Task.Factory.StartNew(() => library.SomeAPI(x) );
}
}
}
好吧,您可以使用 CountdownEvent
轻松等待所有这些。您在开始时设置它的大小,在每个 library.Clean()
之后发出信号并使用 Wait()
:
private CountdownEvent _countdownEvent;
public void Cancel()
{
cs.Cancel();
_countdownEvent.Wait();
// Update UI
}
public void StartProcessing()
{
try
{
_countdownEvent = new CountdownEvent(_Employees.Count);
Task[] tasks = this._Employees.AsParallel().WithCancellation(cs.Token).Select(x => this.ProcessThisEmployee(x, cs.Token)).ToArray();
Task.WaitAll(tasks);
}
catch (AggregateException ae)
{
// error handling code
}
// other stuff
}
private async Task ProcessThisEmployee(Employee x, CancellationToken token)
{
ThirdPartyLibrary library = new ThirdPartyLibrary();
token.ThrowIfCancellationRequested();
using(token.Register(() => { library.Clean(); _countdownEvent.Signal(); })
{
await Task.Factory.StartNew(() => library.SomeAPI(x) );
}
}
但是,您需要意识到,您尝试执行的操作可能很危险,因为您无法控制何时启动取消。如果您的一些员工在 using 块之前或之后并且您取消了操作 library.Clean
将不会被调用,因此您可以永远等待它。