为什么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;
    }

为什么上述情况会呈指数级放缓?这就像验证器每次都在重新验证所有对象一样。

为什么Validator.TryValidateObject的速度呈指数级下降

您所描述的是二次运行时,其中每单位工作的成本随着完成的工作量线性增加。

我能看到的最可能的解释是,AddProviderTransparent扩展了一个具有线性搜索时间的列表,要么是因为它使用了线性搜索,要么是由于存在散列冲突和通过bucket的线性搜索。

如果为每个工作单元添加一个新的提供程序,并处理每个单元的整个提供程序列表,那么就会得到二次运行时。

不要在每次调用时都扩展提供程序列表,而是只在所需的提供程序还不在列表中时才这样做。您可以使用HashSet<Pair<Type, Type>>来记住您已经添加的T, U对。