泛型与数组列表

时间:2020-03-06 14:22:34  来源:igfitidea点击:

我在这里工作的系统是在.net 2.0之前编写的,没有使用泛型的好处。最终将其更新为2.0,但是由于时间限制,没有重构任何代码。在很多地方,代码使用ArraysLists等将事物存储为对象。

从性能的角度来看,将代码更改为使用泛型有多重要?我从性能角度,装箱和拆箱等方面知道,它效率不高,但是更改它实际上会带来多少性能提升?是否可以继续使用泛型,还是需要进行足够的性能更改以至于需要良心来更新旧代码?

解决方案

唯一可以确定的方法是使用dotTrace之类的工具来分析代码。

http://www.jetbrains.com/profiler/

装箱/拆箱在我们特定的应用程序中可能是微不足道的,因此不值得重构。展望未来,由于编译时类型的安全性,我们仍应考虑使用泛型。

我们将在维护阶段获得最大的收益。泛型更易于处理和更新,而不必处理转换和转换问题。如果这是我们不断访问的代码,则一定要努力。如果这是多年未触及的代码,我真的不会打扰。

这取决于,最好的答案是分析代码并查看。我喜欢AQTime,但是为此有很多软件包。

通常,如果正在使用ArrayList,则可能需要将其切换为通用版本。确实,我们很可能甚至无法衡量性能差异。装箱和拆箱是额外的步骤,但是现代计算机速度如此之快,几乎没有什么区别。由于ArrayList实际上只是具有良好包装器的普通数组,因此与转换为泛型相比,我们可能会发现,通过更好的数据结构选择(ArrayList.Remove为O(n)!)可以获得更高的性能。

编辑:Outlaw程序员有一个好点,我们仍然会使用泛型进行装箱和拆箱,它只是隐式发生。不过,所有有关围绕演员和" is / as"关键字检查异常和空值的代码都会有所帮助。

自动装箱/拆箱与泛型有什么关系?这只是类型安全问题。对于非泛型集合,我们需要显式地转换回对象的实际类型。使用泛型,我们可以跳过此步骤。我不认为一种或者另一种方式会有性能差异。

我的老公司实际上考虑了这个问题。我们采取的方法是:如果容易重构,那就去做;如果不是这样(即会涉及过多的课程),请稍候片刻。这实际上取决于我们是否有时间进行编码,或者是否还有其他重要项目要编码(即我们应该为客户端实现的功能)。

再说一次,如果我们不打算为客户做某事,请继续并花一些时间进行重构。它将为我们自己提高代码的可读性。

无论是Java还是.NET,泛型都应用于设计和类型安全,而不是性能。自动装箱与泛型(本质上是隐式的对象到原始的转换)不同,并且如前所述,如果要进行大量的算术运算或者其他操作会导致性能下降,则不应使用它们代替原始。隐式对象的创建/销毁。

总的来说,我建议我们继续使用,并且仅在需要出于类型安全/设计目的(而不是性能)而对其进行清理的情况下才更新现有代码。

正如我们所说,从技术上讲,泛型的性能更好。但是,除非性能非常重要并且我们已经在其他领域进行了优化,否则我们可能会花时间在其他地方来获得更好的改进。

我会建议:

  • 继续使用泛型。
  • 如果我们有可靠的单元测试,则在触摸代码时重构为泛型
  • 花费其他时间进行重构/测量,这将显着提高性能(数据库调用,更改数据结构等),而不是在这里和那里花费几毫秒的时间。

当然,除了性能之外,还有其他原因可以更改为泛型:

  • 更少的错误倾向,因为我们可以进行类型的编译时检查
  • 更具可读性,我们无需在整个地方进行转换,并且很明显存储在集合中的是哪种类型
  • 如果我们将来使用的是泛型,那么在任何地方使用它们都比较干净

取决于代码中有多少。如果在UI中绑定或者显示大列表,则可能会获得很大的性能提升。

如果ArrayList只是四处散布,那么清理它可能没什么大不了的,但也不会对整体性能产生很大的影响。

如果我们在整个代码中使用了大量ArrayList,并且替换它们(这可能会影响日程安排)会很麻烦,那么我们可以采用"如果我们触摸更改它"的方法。

不过,最主要的是,由于我们能从泛型中获得强大的输入,泛型更易于阅读,并且在整个应用程序中更加稳定。我们不仅会从性能中受益,而且会从代码的可维护性和稳定性中受益。如果我们可以快速完成,那么我会说。

如果我们可以从产品负责人那里买进,我建议我们清理一下。我们之后会更喜欢代码。

如果ArrayLists中的实体是Object类型,则不将其强制转换为正确的类型会有所帮助。如果它们是值类型(如Int32之类的结构或者原语),那么装箱/拆箱过程会增加很多开销,而通用集合应该更快。

这是有关该主题的MSDN文章

这是我从100KB文件的字符串中简单解析100,000次后得到的结果。通用列表(char)花费了612.293秒才能遍历该文件100,000次。
ArrayList花费了2,880.415秒来遍历该文件100,000次。这意味着在这种情况下(由于里程会有所不同),通用列表(字符)快了4.7倍。

这是我运行了100,000次的代码:

Public Sub Run(ByVal strToProcess As String) Implements IPerfStub.Run
    Dim genList As New ArrayList

    For Each ch As Char In strToProcess.ToCharArray
        genList.Add(ch)
    Next

    Dim dummy As New System.Text.StringBuilder()
    For i As Integer = 0 To genList.Count - 1
        dummy.Append(genList(i))
    Next

End Sub

 Public Sub Run(ByVal strToProcess As String) Implements IPerfStub.Run
     Dim genList As New List(Of Char)

     For Each ch As Char In strToProcess.ToCharArray
         genList.Add(ch)
     Next

     Dim dummy As New System.Text.StringBuilder()
     For i As Integer = 0 To genList.Count - 1
         dummy.Append(genList(i))
     Next
 End Sub

泛型具有更好的性能,尤其是当我们使用值类型(int,bool,struct等)时,我们将获得明显的性能提升。

  • 将Arraylist与值类型一起使用会导致装箱/拆箱,如果执行数百次,则装箱/装箱会比使用常规List慢得多。
  • 当将值类型存储为对象时,每个项目最多可存储四个时间。虽然这个数量不会耗尽RAM,但是较小的缓存可能包含较少的项目,这意味着在迭代较长的集合时,将从主内存到缓存的副本很多,这会使应用程序变慢。

我在这里写过。

如果我们想在以后的版本中使用linq之类的东西,使用泛型还应该意味着代码将更简单易用。