在 CodeFluent 中使用 List 时收集速度慢

Slow collections when using List in CodeFluent

我在 CodeFluent 中遇到内存泄漏问题,因为对象的 ListCollections 的事件处理程序维护了对我不再需要的对象的引用。解决方案是将实体的集合类型更改为 List 而不是 ListCollection。这解决了内存泄漏问题。

但是,现在我注意到 List 比 ListCollection 慢得多。每次 Codefluent 将对象添加到列表时,如果检查对象是否已经在列表中。这将触发对象中的 BaseContains 方法。 CPU 的 91% 都花在了这里(使用 ANTS 进行分析)。我用 CPU 百分比标记了热路径。

函数 LoadByMainCwEntity 包含以下代码块:

for (readerRead = reader.Read(); ((readerRead == true) 
            && ((count < this.MaxCount) 
            && (count < pageSize))); readerRead = reader.Read())
{
    readCount = (readCount + 1);
    if ((CodeFluent.Runtime.CodeFluentPersistence.CanAddEntity(pageIndex, pageSize, pageOptions, readCount) == true))
    {
        Runtime.CwObject cwObject = new Runtime.CwObject();
        ((CodeFluent.Runtime.ICodeFluentEntity)(cwObject)).ReadRecord(reader);
        91% CPU >> if ((this.BaseContains(cwObject) == false))
        {
            this.BaseAdd(cwObject);
            count = (count + 1);
        }
        cwObject.EntityState = CodeFluent.Runtime.CodeFluentEntityState.Unchanged;
    }
}

这叫做:

protected virtual bool BaseContains(Runtime.CwObject cwObject)
        {
            if ((cwObject == null))
            {
                return false;
            }
            91% CPU >> bool localContains = this.BaseList.Contains(cwObject);
            return localContains;
        }

这叫做:

public virtual bool Equals(Runtime.CwObject cwObject)
    {
        if ((cwObject == null))
        {
            return false;
        }
        29% CPU >> if ((this.Guid.Equals(CodeFluentPersistence.DefaultGuidValue) == true))
        {
            return base.Equals(cwObject);
        }
        45% CPU >> return (this.Guid.Equals(cwObject.Guid) == true);
    }

所有的方法都显得轻巧。我认为问题出在命中数上。如果我有一个包含 100.000 个对象的列表并且 Codefluent 添加数字 100.001,它将检查所有 100.000 个其他对象以找到匹配项。不断增长的集合会以指数方式减慢 .Add 方法的速度。

在 Codefluent 的正常 'load' 操作中检查对象是否已经在集合中似乎有点奇怪。是否有任何解决方法,或者我应该接受大型列表在 Codefluent 中真的很慢的事实?

SoftFluent 创建了一个方面,通过删除一些检查和 genericity 来提高生成代码的性能:blog post, code on GitHub。在 Frans Bouma 提供的基准测试中,使用这个方面,CodeFluent Entities 排名第二,仅次于手工编码查询。

如果您只发现少量加载方法在您的应用程序上下文中速度较慢,您可以创建自定义 C# 方法,使用生成的代码来 return 自定义集合。例如,您可以创建一个方法,其中 return 是一个 IEnumerable<T> 而不是生成的集合:

static IEnumerable<Order> LoadOrders()
{
    using (IDataReader reader = OrderCollection.PageDataLoadAll(null))
    {
        while (reader.Read())
        {
            Order o = new Order();
            o.RaisePropertyChangedEvents = false;
            ((ICodeFluentEntity)o).ReadRecord(reader);
            yield return o;
        }
        CodeFluentPersistence.CompleteCommand(Constants.NorthwindStoreName);
    }
}

更新

当您在表面上 select 一个 属性 时,fastReader 属性应该在 属性 网格中可见。您必须 select "Aspect and Producers Properties" 选项卡:

属性由the aspect添加:

<cf:descriptor name="fastReader" targets="Property" defaultValue="false" displayName="Enable Fast Reader" typeName="boolean" description="Determines if the fast reder is enabled for collection loading." category="Faster Reader Aspect" />

方面删除了自动转换 (CodeFluentPersistence.GetReaderValue) 并期望存储过程 return 所有列。在某些情况下,它可能不起作用。