C# 设置外部类属性“string”和调用方法时如何确保线程安全
我正在致力于代码性能优化。我已经在 MethodA
中实现了 Task.WhenAll
。在 MethodA
中,我选择所有 Customer
对象(也包括客户名称和 Id),然后 MethodA
调用 MethodB
它选择awaitcustomersRecords
。 MethodB
确实与 MethodA
存在于同一类中。
我有外部 MyLogger 类。在 MethodA
中,我需要分配 customerId
((MyLogger)log).CustomerId = customer.Id;
以便它获得每个客户的引用。使用经典循环没问题,但使用多线程时,我有时会得到不同的 customerId
值。我需要确保线程安全
MethodA
public Class MethodA{
private static ILogger log;
public MethodA(ILogger logger){
log = logger;
}
public async Task<List<Customers>> MethodA(){
List<Customer> customers = await GetAllCustomers();
var inboundCustomerFiles= new List<InboundCustomerFiles>();
await Task.WhenAll(customers.Select(async customer =>
{
((MyLogger)log).CustomerId = customer.Id; // need help here...
log.LogDebug($"@@@ Processing Customer :: {customer.Id}:
and Oper8 has customerId {((MyLogger)log).CustomerId} should be same in every thread!");
var processedCustomer = await MethodB(customer);
inboundCustomersFiles.AddRange(processedCustomer);
});
}
}
MethodB
public static async Task<List<InboundCustomerFiles>> MethodB(Customer customer){
var customerRecord = await GetCustomerRecord(customerId);
foreach(var customer in customerRecord){
var folderLocation = await Task.Run(() =>
getCustomerRecordFilesLocation(customerRecordId));
}
return data;
}
MyLogger
public class MyLogger : ILogger
{
public string CustomerId {get; set;}
....
}
I am working on code performance optimizing. I have implemented Task.WhenAll
in MethodA
. In MethodA
I am picking all the Customer
object (that includes customer name and Id too) Then MethodA
calls MethodB
which picks await customersRecords
. MethodB
does exist in same class as MethodA
.
I have external MyLogger class. In MethodA
I need to assign customerId
((MyLogger)log).CustomerId = customer.Id;
so that It get reference for each customer. With classic loop is fine but with multithread I get sometime different values of customerId
. I need to ensure is thread-safe
MethodA
public Class MethodA{
private static ILogger log;
public MethodA(ILogger logger){
log = logger;
}
public async Task<List<Customers>> MethodA(){
List<Customer> customers = await GetAllCustomers();
var inboundCustomerFiles= new List<InboundCustomerFiles>();
await Task.WhenAll(customers.Select(async customer =>
{
((MyLogger)log).CustomerId = customer.Id; // need help here...
log.LogDebug(quot;@@@ Processing Customer :: {customer.Id}:
and Oper8 has customerId {((MyLogger)log).CustomerId} should be same in every thread!");
var processedCustomer = await MethodB(customer);
inboundCustomersFiles.AddRange(processedCustomer);
});
}
}
MethodB
public static async Task<List<InboundCustomerFiles>> MethodB(Customer customer){
var customerRecord = await GetCustomerRecord(customerId);
foreach(var customer in customerRecord){
var folderLocation = await Task.Run(() =>
getCustomerRecordFilesLocation(customerRecordId));
}
return data;
}
MyLogger
public class MyLogger : ILogger
{
public string CustomerId {get; set;}
....
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以使用锁,但它会序列化所有调用。
更好的方法是避免共享可变状态。因此,要么更改
MyLogger
中的所有方法以接受客户 ID 作为参数,然后更改所有日志记录以提供此参数。或者为客户创建新的MyLogger
对象并更改代码以使用此对象而不是共享对象。例如,将记录器更改为
现在类是不可变的。因此,如果您想创建带有客户 ID 的记录器,您需要创建一个新对象并将该对象传递给需要记录器的任何方法或类。这解决了许多问题,您不再关心日志对象是什么类型,因为您总是会创建一个新的装饰器。记录器现在是不可变的,因此您无需关心调用过程中属性的更改,并且它有助于强制实施正确的设计。
一般来说,任何类型的共享可变状态都会使任何类型的多线程变得困难。尽可能使用不可变对象和局部变量要安全得多。
You could use a lock, but it would serialize all the calls.
A better approach would be to avoid shared mutable state. So either change all the methods in
MyLogger
to accept the customer Id as a parameter, and change all your logging to give this parameter. Or create newMyLogger
objects for customer and change your code to use this object instead of the shared object.For example, change your logger to
Now the class is immutable. So if you want to create a logger with a customer Id you need to create a new object and pass this object to whatever method or class needs the logger. This solves many issues, you no longer care what type the log object is, since you will always create a new decorator. The logger is now immutable, so you do not need to care about the property changing in the middle of a call, and it helps enforce a correct design.
In general, shared mutable state of any kind will make any kind of multi threading difficult. It is far safer to use immutable objects and local variables as much as possible.