代码之家  ›  专栏  ›  技术社区  ›  pierroz

更改为通用接口对性能的影响

  •  6
  • pierroz  · 技术社区  · 16 年前

    我使用Visual Studio在C#/.NET中开发应用程序。在我的方法原型中,ReSharper经常建议我用更通用的参数替换输入参数的类型。例如,列表<&燃气轮机;使用IEnumerable<&燃气轮机;如果我只在方法体中使用带有foreach的列表。我可以理解为什么写这个看起来更聪明,但我很关心它的性能。我担心如果我听ReSharper,我的应用程序的性能会下降。。。

    有人能准确地(或多或少地)向我解释一下在我写作时幕后(即CLR)发生的事情吗:

    public void myMethod(IEnumerable<string> list)
    {
      foreach (string s in list)
      {
        Console.WriteLine(s);
      }
    }
    
    static void Main()
    {
      List<string> list = new List<string>(new string[] {"a", "b", "c"});
      myMethod(list);
    }
    

    public void myMethod(List<string> list)
    {
      foreach (string s in list)
      {
        Console.WriteLine(s);
      }
    }
    
    static void Main()
    {
      List<string> list = new List<string>(new string[] {"a", "b", "c"});
      myMethod(list);
    }
    
    10 回复  |  直到 14 年前
        1
  •  11
  •   Jon Skeet    16 年前

    您担心性能-但是您有任何理由担心吗?我的猜测是,您根本没有对代码进行基准测试。 在用更高性能的代码替换可读、干净的代码之前进行基准测试。

    在本例中,调用 Console.WriteLine 无论怎样,他都将完全主宰这场演出。

    虽然我怀疑可能有 List<T> IEnumerable<T> 在这里,我怀疑在现实世界的应用程序中,它的重要性是非常小的。

    它甚至不像序列类型被用于许多操作——只有一个调用 GetEnumerator() 被宣布返回 IEnumerator<T> 无论如何随着列表越来越大,两者在性能上的任何差异都会趋于平衡 更小 ,因为它只会在循环开始时产生任何影响。

    测量 在您将编码决策建立在性能之上之前。

    IEnumerable<T> 然后调用相应方法的代码。就 列表<T>

        2
  •  3
  •   John Saunders    16 年前

    弗雷奇 语句始终对IEnumerable或 IEnumerable<T> . 即使你指定 List<T> ,它仍然必须获得 IEnumerable<T> 为了迭代。

        3
  •  2
  •   sehe    14 年前

    一般来说,我会说,如果您要用泛型风格替换等效的非泛型接口(比如 IList<> --&燃气轮机; IList<T> )你一定会成功的 较好的 或同等性能。

    支持真值类型( struct ),其中一个主要区别在于其存储方式,例如 List<int> 内部。这可能会很快成为一个很大的差异,这取决于列表的使用强度。


    一项脑残的合成基准测试显示:

        for (int j=0; j<1000; j++)
        {
            List<int> list = new List<int>();
            for (int i = 1<<12; i>0; i--)
                list.Add(i);
    
            list.Sort();
        }
    

    快一倍 比半等效非通用:

        for (int j=0; j<1000; j++)
        {
            ArrayList list = new ArrayList();
            for (int i = 1<<12; i>0; i--)
                list.Add(i);
    
            list.Sort();
        }
    

    免责声明 我意识到这个基准是合成的,它实际上并不关注 接口 就在这里(相当直接地分派对特定类型的虚拟方法调用)等等。然而,它说明了我的观点。 不要害怕仿制药 (至少不是出于性能原因)。

        4
  •  1
  •   CookieOfFortune    16 年前

    一般来说,增加的灵活性将值得它带来的微小性能差异。

        5
  •  1
  •   Ahmed    16 年前

    第二个版本将该方法限制为接受sepcific类类型,不建议这样做。而且性能基本相同。

        6
  •  1
  •   Timothy Carter    16 年前

    此建议的基本原因是创建一个适用于IEnumberable和List的方法是为了将来的灵活性。如果将来需要创建MySpecialStringsCollection,可以让它实现IEnumerable方法,并且仍然使用相同的方法。

    从本质上说,我认为它是下降的,除非你注意到一个重要的,有意义的性能打击(如果你注意到任何,我会感到震惊);更喜欢一个更宽容的界面,它将接受比您现在期望的更多的内容。

        7
  •  1
  •   Robert Harvey    16 年前

    List<T> 是:

    [SerializableAttribute]
    public class List<T> : IList<T>, ICollection<T>, 
        IEnumerable<T>, IList, ICollection, IEnumerable
    

    所以 列表<T> 源于 IList , ICollection , IList<T>, ICollection<T>, 除了 IEnumerable IEnumerable<T>.

    这个 数不清 接口公开了 GetEnumerator IEnumerator A. MoveNext Current 所有物这些机制是什么 列表<T> 类用于使用foreach和next遍历列表。

    IList, ICollection, IList<T>, and ICollection<T> 如果不需要做这项工作,那么使用 数不清 IEnumerable<T>

        8
  •  0
  •   GalacticCowboy    16 年前

    接口只定义类实现的公共方法和属性的存在和签名。由于接口不是“独立的”,因此应该有 方法本身的性能差异,以及任何“铸造”惩罚(如果有)都应该太小而无法衡量。

        9
  •  0
  •   clemahieu    16 年前

    正如其他人所说,过早优化是万恶之源。编写代码,通过热点分析运行代码,然后再考虑性能优化问题。

        10
  •  0
  •   DiVan    14 年前

    进入IEnumerable<&燃气轮机;可能会造成一些麻烦,因为您可能会收到执行不同的LINQ表达式,或者产生返回。在这两种情况下,您都不会有收藏,但 某物 你可以在上面重复。 因此,当您想要设置一些边界时,可以请求一个数组。打电话没问题 在传递参数之前,但您将确保没有隐藏的不同警告。

    推荐文章