【问题标题】:Load a List More Efficiently更有效地加载列表
【发布时间】:2013-03-11 21:19:59
【问题描述】:

我的任务是更新一些遗留代码,并且确实需要减少部分代码的运行时间。下面的列表经常加载。我已经设法将时间从大约一分钟减少到大约十五秒,但它确实需要进一步减少。以下代码行运行良好,但我正试图从中挤出一切。

List<MyObject> _moList = new List<MyObject>(DB.GetAll(queryString, parameters, MyObject.Extract));
_moList.AsParallel().ForAll(s => s.RelativeCost = GetRelativeCost(s));

所以我有几个问题。首先,是否可以将这两行合并为一行,如果可以,如何?其次,这样做会提高性能吗?

有些不是 MyObject 有大约 40 个属性(不确定这是否相关),而 GetRelativeCost 在时间/cpu 周期方面有些昂贵(因此并行运行)。

任何帮助将不胜感激!

附:我也在研究其他角度,特别是试图降低 GetRelativeCost 的“成本”,但我需要让每个周期都能摆脱它,以使其为用户所接受。

【问题讨论】:

  • 看起来您要访问数据库...您是否分析了查询以查看是否可以加快速度?
  • 您是否希望在每次运行时提高平均性能(超过应用程序的反抗寿命)或最坏情况下的性能?如果是前者,您可以尝试每次缓存结果并测试以查看源数据是否在重新加载之前发生更改。
  • 你为什么用AsParallel而不是Parallel.ForEach
  • kzhen - 是的 Pieter - 是前者,我会看看有没有办法做到这一点 Zaid - 没有理由。是否有理由使用其中一个?

标签: c# performance lambda parallel-extensions


【解决方案1】:
  1. 您是否运行了分析器?您确定要优化瓶颈吗?
  2. 为什么要优化列表处理而不是GetRelativeCost
  3. 什么是DB.GetAll?您确定它以最佳方式工作吗?
  4. 我是否认为MyObject.Extract 是某种对象水合功能?你确定它是最优的吗?
  5. 为什么GetRelativeCost 在列表加载时被执行?推迟执行不是有意义吗?

关于最后一点的更多信息。如果你的GetRelativeCost 有一些副作用 - 你最好还是删除它们,因为它违反了 DRY 原则。如果没有,您可能需要重写 RelativeCost 以允许延迟初始化,例如

private int? _relativeCost
public int RelativeCost {
    get {
       if  (!_relativeCost.HasValue)
            _relativeCost = GetRelativeCost();
       return _relativeCost;
    }
}

这样您可以延迟GetRelativeCost 的执行,直到它真正需要为止。通过这种方式,您可以通过不计算 GetRelativeCost 来优化不需要设置 RelativeCost 的实体,并通过延迟 GetRelativeCost 中昂贵的计算来加速 特定代码以以后增加计算为代价。

总结:运行profiler,确定瓶颈,优化瓶颈。如果瓶颈出现在GetRelativeCost - 尝试按照我上面的描述让它变得懒惰。

【讨论】:

  • 1.是的,几次 2. 我也在尝试优化获得相对成本 3. 无法控制这一点。 DB.GetAll 指的是我没有源代码的第三方程序集。要删除所有引用将需要对代码进行重大重写。 4. 我愿意接受建议。见下文。
  • 5. a - 下一行是_objectCache = new List&lt;MyObjectDisplayer&gt;(_moList.Select(s =&gt; new MyObjectDisplayer(s))); 然后我必须通过另一个对象访问该对象。将其移至列表负载将我的时间减少了约 10%。
  • b - MyObject 是更大结构的一部分。要计算成本,它必须了解那个更大的结构。例如,较大的结构可能有 48 英寸宽。 MyObject 可以是 8、12、24 或 48 英寸。 8 英寸的成本比 48 英寸的要高,因为它需要使用 6 个。通过让 MyObject 知道其父对象来进行延迟加载会更好,还是让父对象根据子对象计算成本?
  • public static IEnumerable&lt;DynasonicsSilencer&gt; Extract(DbDataReader dr) { int oModelNumber = dr.GetOrdinal("ModelNumber"), oIsStandardProduct = dr.GetOrdinal("IsStandardProduct"), oManufacturerName = dr.GetOrdinal("ManufacturerName"), ... while (dr.Read()) { yield return new MyObject() { ModelNumber = dr.GetString(oModelNumber), IsStandardProduct = dr.GetBoolean(oIsStandardProduct), ManufacturerName = dr.GetString(oManufacturerName), ... }; } }
  • @OpusKrokus 请更新问题。 cmets 中的代码很难阅读,甚至更难理解。另外,我认为如果您发布GetRelativeCost函数也不会造成伤害
【解决方案2】:

您可以通过删除变量并在 new 的结果上调用 AsParalel 将它们组合成一行。

(new List<MyObject>(DB.GetAll(queryString, parameters, MyObject.Extract))).AsParallel().ForAll(s => s.RelativeCost = GetRelativeCost(s));

但是,不要指望这会提高代码的性能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-11
    • 2022-01-19
    • 1970-01-01
    • 2021-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多