【问题标题】:Will the compiler optimize away creating this list twice?编译器会优化两次创建此列表吗?
【发布时间】:2010-11-09 11:50:54
【问题描述】:
public SharpQuery Add(params HtmlNode[] elements)
{
    var nodes = new List<HtmlNode>(_context.Count + elements.Length);
    nodes.AddRange(_context);
    nodes.AddRange(elements);
    return new SharpQuery(nodes, this);
}

public SharpQuery(IEnumerable<HtmlNode> nodes, SharpQuery previous = null)
{
    if (nodes == null) throw new ArgumentNullException("nodes");
    _previous = previous;
    _context = new List<HtmlNode>(nodes);
}

我有一大堆函数可以创建一个新的List&lt;T&gt;,向其中添加一堆节点,然后将其传递给构造函数,该构造函数获取列表,并用它创建另一个新列表。

编译器是否足够聪明,可以确定它实际上不需要创建两次列表?

【问题讨论】:

  • 您能否考虑让问题标题更具体一些?像这样的问题标题往往会导致重复。
  • @Andre:抱歉,很难想出一个标题来捕获该信息而不显示代码。
  • 没问题。现在好多了:)

标签: c# optimization compiler-construction


【解决方案1】:

这不是“足够聪明”的情况——编译器会按照它的指示去做;您是在告诉它创建多个列表:它将创建多个列表。

但是,由于您及时释放它们,它们应该被相当干净地收集起来,希望是 gen-0。因此,除非您在一个紧密的循环中执行此操作,否则我不会对此感到太兴奋。

如果您想避免使用列表,可能考虑使用 LINQ Concat,它允许您在没有任何额外列表/集合/等的情况下附加序列。

【讨论】:

  • 如何在不创建额外列表的情况下 concat 工作?我看到它适用于可枚举,但我无法创建可枚举...?
  • ...没关系。古法的回答回答了这个问题。我连接到上下文,这不会修改上下文,只是为它提供了一个枚举。酷:)
【解决方案2】:

如果你告诉它创建一个新对象,它就会创建一个新对象。我不认为有一种优化可以用强制转换和分配替换构造函数调用 - 编译器必须非常了解构造函数的作用才能以这种方式对其进行优化。

从技术上讲,你可以自己做 - _context = (List&lt;HtmlNode&gt;)nodes; - 这就是你希望编译器做的事情。或者,更好的是_context = nodes as List&lt;HtmlNode&gt; ?? new List&lt;HtmlNode&gt;(nodes)
但无论哪种情况,列表都可能在您的班级之外进行修改,因此您必须确保它不会导致意外行为。

到目前为止,它闻起来有点过早的优化。您的代码看起来不错,在看到实际性能问题之前我不会更改任何内容。

【讨论】:

  • 嗯,这是一个图书馆。我在使用中可能没有任何性能问题,但其他人可能。它更多的是学习如何正确地做事,而不是微优化。
  • 我不知道你可以像这样投射一个枚举......但即使我可以,我也不喜欢它,因为它需要复制以防止在课堂外修改。只有在通过 Add() 调用它的情况下,我才需要它来创建一个新的。
  • 好吧,您可以创建一个私有构造函数来获取一个列表并按原样存储它,以及一个复制成员的公共收缩器。然后你可以从 Add() 和其他你控制列表来源的地方调用私有构造函数。
【解决方案3】:

不,编译器不能做这样的优化。

由于构造函数采用 IEnumerable,因此您可以创建表达式而不是列表:

public SharpQuery Add(params HtmlNode[] elements) {
  return new SharpQuery(_context.Concat(elements), this);
}

Concat 方法将创建一个表达式,该表达式首先返回 _context 的项目,然后是 elements 的项目。在构造函数中创建列表时,它将使用直接从_contextelements 读取的表达式,因此该集合只创建一次。

【讨论】:

  • 请注意,Union 与添加两个列表不同,因为 Union 是不同的;你的意思是Concat
  • @Marc Gravell:很好,Concat 是我的意思。
【解决方案4】:

(JIT 的)编译器无法对此进行优化。它会为您创建两个列表。然而,问题是,这是否会给您带来性能问题。有了性能,你就有了衡量、衡量和衡量。在 98% 的情况下,我认为这段代码不会出现任何问题。

【讨论】:

    猜你喜欢
    • 2011-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-11
    • 2017-04-24
    • 1970-01-01
    • 2016-06-01
    • 2017-01-27
    相关资源
    最近更新 更多