我正在通过验证器列表验证请求对象:
foreach (var validator in validators)
{
results.Add(validator.Validate(request));
}
每个验证器检查对象,可能会或可能不会向请求对象的错误列表添加错误(List< OrderWarningError>)
public override bool? Validate(Request request)
{
bool isValid = true;
if (someErrorConditionIsMet)
{
isValid = false;
request.WarningsErrors.Add(new OrderWarningError
{
Message = "The request contains an error",
Severity = EnumWarningErrorSeverity.Error
});
}
return isValid;
}
我现在正在添加更多验证器,每个验证器可能依赖于其业务规则的外部数据,因此我希望同时运行每个验证器以提高性能。在Add()期间同步访问通用列表属性而不更改其数据类型的最佳方法是什么(这是否可能)?
我可以这样做吗?:
lock (request.WarningsErrors)
{
request.WarningsErrors.Add(new OrderWarningError
{
Message = "The request contains an error",
Severity = EnumWarningErrorSeverity.Error
});
}
答案 0 :(得分:2)
您可以使用lock yes,但最好使用类似于名称空间“System.Collections.Concurrent”中定义的线程安全集合。
答案 1 :(得分:1)
对于集合的并发访问,有一些问题可能会出错,所以让我们看看它们是否适用:
ConcurrentModificationException
。注意:如果您在同一个线程中迭代它时尝试修改集合,则可以获取这些集合。在您的方案中,您正在添加每个验证程序唯一的错误等。只要订单不重要,您就不需要锁定您的收藏。在尝试迭代集合之前,您只需确保完成处理。 在这种特殊情况下,您可以使用任何集合来存储结果。
为了提高安全性,以及在发生潜在修改时进行迭代的能力,您可能需要查看ConcurrentBag
或ConcurrentQueue
。 (两者都在System.Collections.Concurrent中)。
请记住,并行处理您的验证可能无法为您提供您可能认为会获得的性能优势。
为了使并行处理有意义,您必须处理阻塞I / O或其他导致验证需要很长时间的资源密集型任务。如果您的整个验证时间不到100毫秒(0.1秒),那么并行处理只会使挂钟时间花费更长时间,代价更复杂。
在迭代错误列表之前确保所有处理完成的最简单的构造是Parallel.ForEach
构造。但我建议使用Stopwatch
来检验假设。