正如您在下面的代码中所看到的,为每个Employee调用ProcessThisEmployee。在该方法中,当取消操作时,我调用第三方库的Clean方法。 让我们说Clean方法需要相当多的时间。我想要做的是在完成ProcessThisEmployee方法的所有正在运行的实例的Clean方法时在UI中显示一些消息。 这意味着我需要等待所有Clean方法的完成。现在,我有一个WaitAll for tasks但我不确定它是否会等待所有的canellations也完成。有什么想法吗?
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) );
}
}
}
答案 0 :(得分:2)
好吧,您可以使用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
,因此您可以永久等待它。