正如你在下面的代码中看到的,ProcessThisEmployee 是为每个 Employees 调用的。在该方法中,当操作取消时,我调用第三方库的 Clean 方法。假设清洁方法需要相当多的时间。我想做的是在完成 ProcessThisEmployee 方法的所有正在运行实例的清理方法时在 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) );
}
}
但是,您需要意识到,您尝试执行的操作可能是危险的,因为您无法控制何时启动取消。如果您的一些员工在使用块之前或之后,并且您取消了操作library.Clean
将不会调用,因此您可以永远等待它。