[英]Is it a reasonable approach for lock-free design for this scenario
This is kind of follow up to one of my earlier question here . 这是我在此之前提出的一个问题的跟进。 In summary I am trying to come up with a lock free design for this scenario where I upon cancellation of task I want to call a method of third party library.
总之,在这种情况下,我想提出一种无锁设计,在这种情况下,我在取消任务后想调用第三方库的方法。 In response to my question, a helpful SO participant suggested to use CancellationToken.Register but I am not sure where and how can I use that here.
为了回答我的问题,一个有帮助的SO参与者建议使用CancellationToken.Register,但我不确定在这里和在哪里可以使用它。 Below is code that I come up with.
下面是我想出的代码。 Please let me know if you see any issue with this approach or if there are any better alternatives to solve this problem.
如果您发现此方法有任何问题,或者是否有更好的替代方法可以解决此问题,请告诉我。
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();
if (token.IsCancellationRequested)
token.ThrowIfCancellationRequested();
await Task.Factory.StartNew(() => library.SomeAPI(x) );
if (token.IsCancellationRequested)
{
library.Clean();
token.ThrowIfCancellationRequested();
}
}
}
Your process code can be simplified to the following (here is how you use Register) 您的过程代码可以简化为以下内容(这是注册的使用方式)
private void ProcessThisEmployee(Employee x, CancellationToken token)
{
ThirdPartyLibrary library = new ThirdPartyLibrary();
token.ThrowIfCancellationRequested();
using(token.Register(() => library.Clean())
{
library.SomeAPI(x);
}
token.ThrowIfCancellationRequested(); //Not sure why you cancel here in your original example.
}
If the token is canceled while within the scope of the using
statement it will call library.Clean()
if it is called afterwards it does not call the function. 如果令牌在
using
语句范围内被取消,它将调用library.Clean()
如果之后被调用,则不调用该函数。 I also got rid of your Task.Run
, there is no reason to waste the extra thread for what you are doing. 我也摆脱了您的
Task.Run
,没有理由浪费多余的线程做您的工作。 Lastly I got rid of the extra if (token.IsCancellationRequested)
checks, ThrowIfCancellationRequested()
has that if check inside of itself, you don't need to check beforehand. 最后,我摆脱了额外的
if (token.IsCancellationRequested)
检查, ThrowIfCancellationRequested()
拥有如果在其内部进行检查,则无需事先检查。
Also, because in my simplification you are not returning tasks anymore your StartProcessing code becomes 另外,由于我的简化,您不再返回任务,因此StartProcessing代码变为
public void StartProcessing()
{
try
{
this._Employees.AsParallel().WithCancellation(cs.Token).ForAll(x => this.ProcessThisEmployee(x, cs.Token));
}
catch (AggregateException ae)
{
// error handling code
}
// other stuff
}
using ForAll(
instead of Select(
使用
ForAll(
而不是Select(
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.