为什么Validator.TryValidateObject的速度呈指数级下降
本文关键字:指数 速度 Validator TryValidateObject 为什么 | 更新日期: 2023-09-27 18:24:57
我查询一个远程服务,一次接收一批100个产品,并继续这样做,直到不再有批次。我将这100个产品重新映射到我自己的产品对象,我希望一次一个地验证并保存到数据库中。如果其中一个没有验证,我会记录错误并继续处理其余的错误。处理完前100个错误后,我会得到下一批100个错误。总共约有5000人。
在对我的网站进行分析后,我看到的问题是Validator.TryValidateObject的运行时间似乎越来越长。第一批1000花了10分钟,第二批1000花20分钟,第三批1000花30分钟。所以每次似乎要多花10分钟。
Product类有一个伙伴类ProductValidation,其中包含用于验证的适当数据注释。我称之为产品。IsValid()。
public class Product{
public bool IsValid()
{
return this.IsValid<Product, ProductValidation>();
}
}
使用以下代码:
public static bool IsValid<T, U>(this T obj)
{
if (typeof(T) != typeof(U))
{
TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(T), typeof(U)), typeof(T));
}
var validationContext = new ValidationContext(obj, null, null);
var validationResults = new List<ValidationResult>();
//The line below slows everything down. If commented out all is fine
Validator.TryValidateObject(obj, validationContext, validationResults, true);
if (validationResults.Count > 0)
return false;
else
return true;
}
为什么上述情况会呈指数级放缓?这就像验证器每次都在重新验证所有对象一样。
您所描述的是二次运行时,其中每单位工作的成本随着完成的工作量线性增加。
我能看到的最可能的解释是,AddProviderTransparent
扩展了一个具有线性搜索时间的列表,要么是因为它使用了线性搜索,要么是由于存在散列冲突和通过bucket的线性搜索。
如果为每个工作单元添加一个新的提供程序,并处理每个单元的整个提供程序列表,那么就会得到二次运行时。
不要在每次调用时都扩展提供程序列表,而是只在所需的提供程序还不在列表中时才这样做。您可以使用HashSet<Pair<Type, Type>>
来记住您已经添加的T, U
对。