【问题标题】:C# Efficiency for method parameters方法参数的 C# 效率
【发布时间】:2017-04-09 19:18:32
【问题描述】:

我这样说对吗:

public static void MethodName{bool first, bool second, bool third}
{
   //Do something
}

比这更有效率:

public static void MethodName{bool [] boolArray}
{
    bool first = boolArray[0]; 
    bool second = boolArray[1];
    bool third = boolArray[2];
    //Do something
}

我的想法是,他们都必须声明第一、第二和第三——只是在不同的地方。但是对于第二个,它必须将其添加到一个数组中,然后再次解包。

除非你像这样声明数组:

MethodName(new[] { true, true, true });

在哪种情况下我不确定哪个更快?

我之所以问是因为我正在考虑使用第二个,但想知道这对性能是否/有什么影响。

在这种情况下,性能并不是特别重要,但澄清这一点对我会有所帮助。

另外,第二个的优点是你可以传递任意数量的值,而且我认为它也更容易阅读?

我之所以考虑使用它,是因为已经有大约 30 个参数被传递到该方法中,我觉得继续添加更多参数会变得令人困惑。所有这些布尔值都密切相关,所以我认为打包它们可能会使代码更易于管理。

我正在处理现有代码,花时间重新设计方法以减少传递给方法的参数数量不在我的项目范围内,但我认为了解此方法的含义是一种很好的做法改变。

【问题讨论】:

  • 高效如何?在调用不同方法所花费的时间方面更有效?在用于参数的内存方面更有效?在调试这种方法的时间(即开发时间)方面效率更高?
  • 即使执行大量操作,也可能没有明显的性能变化。如果您想“传递任意数量的值”,params 关键字也值得研究 see here
  • 在这种情况下我不确定哪个更快? - 运行这两种方法并比较哪个更快
  • 过于简单的性能分析 - 差别很小:rextester.com/ZWNB22061 在某处添加单个数据库调用,这将不会成为一百万年后的瓶颈。
  • 我已经添加了一个答案,但是 StackOverflow 应该添加一种新的关闭投票,其中应该包含这个标题:过早的优化是万恶之源。哈哈

标签: c#


【解决方案1】:

在性能方面,只有答案for your question

“程序员浪费大量时间思考,或者 担心他们程序中非关键部分的速度,以及 这些提高效率的尝试实际上产生了强烈的负面影响 在考虑调试和维护时。我们应该忘记 小效率,说大约 97% 的时间:过早优化 是万恶之源。然而我们不应该放弃我们的机会 在那个关键的 3% 中。”

在生产力方面,parameters > arrays

旁注

每个人都应该知道这是 Donald Knuth 在 1974 年所说的。在这句话发表 40 多年后,我们仍然在过早优化(甚至毫无意义的优化)经常!

进一步阅读

我会看看另一个Q&A on Software Engineering

【讨论】:

  • 没错,但 Knuth 在一篇文章中写道,尽管 Dijkstra 最近的“Go To Considered Harmful”让函数的速度提高了 13%,但他非常乐意使用 goto。这篇文章作为一个整体强烈支持让事情变得更有性能,仅引用了关于何时何地这样做的建议。虽然 OP 说它在特定情况下并不重要,但整个问题可能与实际情况相关。在你意识到你确实需要它之后,这并不为时过早。
  • @JonHanna 但是你知道,在 99.999999999% 的情况下,你不可能需要在数组上避免参数......
  • @JonHanna 显然,自从 Knuth 写了那篇文章以来,时代已经发生了变化。可能像他这样的人不会在 2016 年写一篇文章、书籍或任何东西来捍卫 goto。但我怀疑一篇优化文章会谈论使用数组而不是参数......对我来说,它应该是编译器优化而不是而不是用高级语言处理这种优化。
  • 我知道他仍然坚持为goto 辩护(我仍然同意)。但是如今,当它确实很重要时,单独的参数与单个数组参数确实是性能工作中涉及的东西。出于这个原因,存在与params 数组一起提供多个参数的框架重载。 (并且已经对框架代码进行了相当多的调整,以确保调用前者而不是后者,纯粹是为了性能影响)。
【解决方案2】:

我这样说是否正确: 比这更有效率:

单独来看,是的。除非调用者已经拥有该数组,在这种情况下,第二个是相同的,甚至(对于更大的参数类型或更多参数)更快。

我问是因为我正在考虑使用第二个,但想知道它是否/对性能有什么影响。

你为什么要考虑第二个?如果在调用时它更自然,那么让它更自然的原因可能也会对性能产生影响,使第二个在更广泛的背景下变得更好,超过这个。

如果您从三个单独的布尔值开始,并且包装它们只是为了再次打开它们,那么我看不出这在实践中提供了什么,除了更多的输入。

所以你考虑这个的原因在这里更重要。

在这种情况下,性能并不是特别重要

那就真的不用担心了。它以命中params 的热路径代码而闻名,它提供采用设定数量的单个参数的重载,但它确实只对热路径产生影响。如果您不在热门路径中,那么选择两者中的任何一个确实更有效的计算时间节省的生命周期不太可能加起来 您在这里写帖子花费的时间。

如果您处于热门路径并且确实需要减少每一纳秒,因为您循环的次数太多以至于它会加起来成为真实的东西,那么您有 测量。孤立的更改在性能方面具有非孤立的影响,因此如果更广泛的上下文意味着调用 A 的代码比 B 慢,那么 Internet 上的人是否告诉您 A 比 B 快并不重要。衡量。第一个衡量标准是“我什至可以注意到吗?”,如果该衡量标准的答案是“否”,那么不要理会它,而是找到可以明显影响性能的地方进行优化。

先编写“自然”的代码,然后再看看小调整是否会对实际伤害您的部分产生性能影响。这不仅仅是因为可读性等的重要性,还因为:

  1. 给定语言中的代码越“自然”,通常效率越高。即使您认为不可能,它也更有可能受益于幕后的一些编译器优化。
  2. 在必要时,更“自然”的代码比做一堆奇怪事情的代码更容易调整性能。

【讨论】:

  • 我之所以考虑使用它是因为已经有大约 30 个参数被传递到该方法中,我觉得继续添加更多参数变得令人困惑。所有这些布尔值都密切相关,所以我认为打包它们可能会使代码更易于管理
  • @Alex 那么你没有性能问题,而是设计问题,因为你的方法(可能还有你的类)做得太多了。始终考虑单一责任原则。
  • 30 将不同于 3 这里如果这是一个快速路径的情况并且性能确实很重要,但是你必须再次测量,因为无论哪个单独获胜都不一定在更广泛的背景下获胜(并在您的测量中包括构建阵列所花费的时间)。正如@HimBromBeere 所说,您遇到了设计问题,可能需要使用不同的方法。 [Flags] 枚举可以容纳 30 个布尔值(32 个,一个基于 long 另一个 32)并且可能更易于使用。至少使用命名参数调用可能会使调用更具可读性:...
  • ...MethodName(true, false, false, true…MethodName(dummyRun: true, recordProgress: false, … 或其他任何东西都更难阅读。
  • 考虑创建一个结构并在这个结构中对参数进行分组?将 ref 向下传递给结构。我同意 HimBromBeere 的观点,您应该考虑拆分班级并选择更好的设计,但在现实生活中,这并不总是允许/可能这样做
【解决方案3】:

我认为这根本不会影响您应用的性能。

个人

我会选择第一个选项,原因有两个:

  1. 为每个参数命名:如果项目是一个大型项目并且有很多编码或未来可能的编辑和增强。
  2. 可用性:如果要发送类似参数的列表,则必须使用数组或列表,如果只是几个参数碰巧属于同一类型,则应分别发送。

【讨论】:

    【解决方案4】:

    第三种方法是使用paramsParams - MSDN

    最后我认为它的性能不会有太大变化。

    array[] 虽然继承自抽象 Array 类,该类实现 IEnumerableIEnumerable<t> (ICloneable, IList, ICollection, IEnumerable, IStructuralComparable, IStructuralEquatable),这意味着对象比三值类型参数更炸毁,这会明显变慢 Array - MSDN

    【讨论】:

    • ;) 我从来没有说过它会让你的应用程序运行得更快,我们中的任何人都可能注意到,但仍然存在差异。这只是你多久调用一次该函数的问题;)我完全同意你上面的回答!
    • 是的,我只是在讽刺模式下这么说;P
    • params 与第二种方式基本相同,只是增加了一些语法糖。 bool[] 继承自 Array 这一事实对数组的大小或直接在其上执行的任何操作的性能(如 bool[])的影响为零。
    • @JonHanna 你是对的,没有派生的属性......我已经改变了。
    • 某事物从其他事物继承这一事实会影响从单个 64 位(在 32 位 .NET 上为 32 位)指向 v 表且没有每个- 实例成本。
    【解决方案5】:

    您可以测试两者的性能差异,但我怀疑会有很大差异。

    您必须考虑可维护性,是其他程序员,甚至您自己会在几周或几个月后了解为什么要这样做吗?它是否易于扩展,您可以将不同的对象类型传递给您的方法吗?

    如果您传递一个项目集合,那么肯定将它们打包到一个数组中会比为每个附加项目指定一个新参数更快吗?

    如果你必须这样做,你可以这样做,但是你考虑过参数数组吗?

    Why use the params keyword?

    public static void MethodName{params bool [] boolAarray}
    {
        //extract data here
    }
    

    【讨论】:

      【解决方案6】:

      同意马蒂亚斯的回答。

      我还想补充一点,您需要添加错误检查,因为您传递了一个数组,并且没有说明您将收到多少个数组元素。因此,您必须首先检查您的数组中是否包含三个元素。这将平衡您可能获得的少量性能增益。

      此外,如果您想将此方法提供给其他开发人员(作为 API 的一部分,无论是公共的还是私有的),智能感知根本不会帮助他们设置他们应该设置的参数...

      虽然使用三个参数,但您可以这样做:

      ///<summary>
      ///This method does something
      ///</summary>
      ///<param name="first">The first parameter</param>
      ///<param name="second">The second parameter</param>
      ///<param name="third">The third parameter</param>
      public static void MethodName{bool first, bool second, bool third}
      {
         //Do something
      }
      

      它会很好地展示给其他人......

      【讨论】:

        【解决方案7】:

        我会采取不同的方法并使用标志;

        public static void MethodName(int Flag) 
        { 
            if (Flag & FIRST) { } 
        } 
        

        编译器可能会进行自己的优化;

        检查http://rextester.com/QRFL3116从Jamiec评论中添加的方法

        • M1 耗时 5ms
        • M2 耗时 23ms
        • M3 耗时 4ms

        【讨论】:

          猜你喜欢
          • 2013-07-18
          • 1970-01-01
          • 2011-09-14
          • 2013-01-17
          • 1970-01-01
          • 2020-10-06
          • 2013-09-21
          • 2017-03-10
          • 1970-01-01
          相关资源
          最近更新 更多