我可以为这种情况设计任何无锁解决方案吗
Can I design any lock-free solution for this scenario
我有一个简单的员工class如下
public class Employee
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
然后我有一个 ProcessEmployees class,它在名为 ProcessThisEmployee 的方法中对这些员工进行并发处理。在这个方法中,我必须调用第三方库方法。到目前为止一切都很简单。问题是有时当用户选择取消此操作时,我需要对任何尚未完成处理的 ThirdPartyLibrary class 实例进行一些清理。请注意,我对 ThirdPartyLibrary class 没有任何控制权,并且它没有任何取消现有任务的机制。它确实提供了一个 Clean 方法,我可以在对 SomeAPI 的调用尚未完成的任何实例上调用该方法。因此,我正在维护所有实例的本地列表。当用户选择取消操作时,我调用 class 的 CleaupIfUserCancelOperation 方法,即我本地列表中的第三方库实例的 Clean 方法。下面是我的代码。
class ProcessEmployees
{
private List<Employee> _Employees;
List<ThirdPartyLibrary> libraries = new List<ThirdPartyLibrary>();
private object sync = new object();
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()
{
Task[] tasks = this._Employees.AsParallel().Select(x => this.ProcessThisEmployee(x)).ToArray();
Task.WaitAll(tasks);
// other stuff
}
private async Task ProcessThisEmployee(Employee x)
{
ThirdPartyLibrary library = new ThirdPartyLibrary();
lock (sync)
{
libraries.Add(library);
}
await Task.Factory.StartNew(() => library.SomeAPI(x) );
lock (sync)
{
libraries.Remove(library);
}
}
private void CleaupIfUserCancelOperation()
{
foreach (ThirdPartyLibrary library in libraries)
library.Clean();
}
}
我必须在这里两次锁定库实例,这当然会影响性能。在这种情况下是否可以使用任何轻量级(无锁)机制?我不太了解并发集合,想知道在这种情况下这些是否有任何用处?
这两个锁调用对性能的影响很可能比您正在执行的其他操作要小得多。假设他们这样做,您可以使用 ConcurrentDictionary
添加和删除实例(无论如何您都不应该使用列表,因为现在并发库数量的性能开销是二次方的)。
最好让每个异步方法自行取消并清理自己的东西。传递给他们 CancellationToken
。使用 Register
注册一个清理库的回调。这里真的不需要global state/collections.
我有一个简单的员工class如下
public class Employee
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
然后我有一个 ProcessEmployees class,它在名为 ProcessThisEmployee 的方法中对这些员工进行并发处理。在这个方法中,我必须调用第三方库方法。到目前为止一切都很简单。问题是有时当用户选择取消此操作时,我需要对任何尚未完成处理的 ThirdPartyLibrary class 实例进行一些清理。请注意,我对 ThirdPartyLibrary class 没有任何控制权,并且它没有任何取消现有任务的机制。它确实提供了一个 Clean 方法,我可以在对 SomeAPI 的调用尚未完成的任何实例上调用该方法。因此,我正在维护所有实例的本地列表。当用户选择取消操作时,我调用 class 的 CleaupIfUserCancelOperation 方法,即我本地列表中的第三方库实例的 Clean 方法。下面是我的代码。
class ProcessEmployees
{
private List<Employee> _Employees;
List<ThirdPartyLibrary> libraries = new List<ThirdPartyLibrary>();
private object sync = new object();
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()
{
Task[] tasks = this._Employees.AsParallel().Select(x => this.ProcessThisEmployee(x)).ToArray();
Task.WaitAll(tasks);
// other stuff
}
private async Task ProcessThisEmployee(Employee x)
{
ThirdPartyLibrary library = new ThirdPartyLibrary();
lock (sync)
{
libraries.Add(library);
}
await Task.Factory.StartNew(() => library.SomeAPI(x) );
lock (sync)
{
libraries.Remove(library);
}
}
private void CleaupIfUserCancelOperation()
{
foreach (ThirdPartyLibrary library in libraries)
library.Clean();
}
}
我必须在这里两次锁定库实例,这当然会影响性能。在这种情况下是否可以使用任何轻量级(无锁)机制?我不太了解并发集合,想知道在这种情况下这些是否有任何用处?
这两个锁调用对性能的影响很可能比您正在执行的其他操作要小得多。假设他们这样做,您可以使用 ConcurrentDictionary
添加和删除实例(无论如何您都不应该使用列表,因为现在并发库数量的性能开销是二次方的)。
最好让每个异步方法自行取消并清理自己的东西。传递给他们 CancellationToken
。使用 Register
注册一个清理库的回调。这里真的不需要global state/collections.