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

从性能角度来看,将代码更改为使用泛型有多重要?我知道从性能的角度来看,装箱和拆箱等,它的效率很低,但是改变它真的能带来多少性能增益呢?泛型是否可以在未来使用,或者是否有足够的性能变化以至于应该做出良心的努力来更新旧代码?

有帮助吗?

解决方案

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

我会建议:

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

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

  • 不易出错,因为您可以在编译时检查类型
  • 更具可读性,您不需要到处进行强制转换,并且集合中存储的类型很明显
  • 如果您以后要使用泛型,那么在任何地方使用它们都会更干净

其他提示

以下是我对 100KB 文件中的字符串进行简单解析 100,000 次后得到的结果。Generic List(Of char) 花费了 612.293 秒来浏览该文件 100,000 次。ArrayList 花费了 2,880.415 秒来浏览该文件 100,000 次。这意味着在这种情况下(当您的里程 将要 变化)通用列表(Of char)快 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

唯一确定的方法是使用 dotTrace 等工具来分析您的代码。

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

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

泛型,无论是 Java 还是 .NET,都应该用于设计和类型安全,而不是性能。自动装箱不同于泛型(本质上是隐式对象到基元的转换),正如您所提到的,如果存在大量算术或其他操作,这将导致重复的性能下降,则不应使用它们来代替基元隐式对象创建/销毁。

总的来说,我建议继续使用,并且仅在出于类型安全/设计目的而不是性能需要清理现有代码时才更新现有代码。

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

一般来说,如果 ArrayList 被大量使用,则可能值得将其切换到通用版本。但实际上,您很可能甚至无法测量性能差异。装箱和拆箱是额外的步骤,但现代计算机速度如此之快,几乎没有什么区别。由于 ArrayList 实际上只是一个带有漂亮包装器的普通数组,因此与转换为泛型相比,您可能会发现通过更好的数据结构选择(ArrayList.Remove 的复杂度为 O(n)!)可以获得更多的性能。

编辑:Outlaw Programmer 有一个很好的观点,您仍然会使用泛型进行装箱和拆箱,这只是隐式发生的。不过,围绕检查强制转换和“is/as”关键字中的异常和空值的所有代码都会有所帮助。

您会在维护阶段发现最大的收获。泛型更容易处理和更新,而不必处理转换和转换问题。如果这是您不断访问的代码,那么请务必付出努力。如果这是多年来没有被触及的代码,我真的不会打扰。

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

我以前的公司其实也考虑过这个问题。我们采取的方法是:如果重构很容易,就重构;如果不是(即它会涉及太多的类),留到以后再说。这实际上取决于您是否有时间去做,或者是否有更重要的项目需要编码(即您应该为客户实现的功能)。

话又说回来,如果您不为客户做某事,请继续花时间进行重构。它将提高您自己代码的可读性。

取决于您的代码中有多少内容。如果您在 UI 中绑定或显示大型列表,您可能会看到性能的巨大提升。

如果你的 ArrayList 只是散落各处,那么清理它可能不会有什么大不了的,而且也不会影响整体性能。

如果您在整个代码中使用了大量 ArrayList,并且替换它们将是一项艰巨的任务(这可能会影响您的日程安排),那么您可以采用“如果您触摸它就更改它”的方法。

不过,最主要的是,泛型更容易阅读,并且由于您从泛型中获得了强类型,因此在整个应用程序中更加稳定。您不仅会看到性能的提升,还会看到代码可维护性和稳定性的提升。如果你能很快做到,我会说做。

如果你能得到产品负责人的支持,我建议你清理它。之后你会更喜欢你的代码。

如果 ArrayList 中的实体是对象类型,那么不将它们转换为正确的类型会带来一些好处。如果它们是值类型(结构体或基元,如 Int32),则装箱/拆箱过程会增加大量开销,并且泛型集合应该更快。

这是关于该主题的 MSDN 文章

泛型具有更好的性能,特别是如果您将使用值类型(int、bool、struct 等),您将获得显着的性能提升。

  1. 将 Arraylist 与值类型一起使用会导致装箱/拆箱,如果进行数百次,则比使用通用 List 慢得多。

  2. 当将值类型存储为对象时,每个项目最多会占用四倍内存。虽然这个数量不会耗尽您的 RAM,但较小的缓存内存可能包含较少的项目,这意味着在迭代长集合时,会有许多副本从主内存到缓存,这会减慢您的应用程序。

我写过关于 这里.

如果您想在更高版本的 C# 中利用 linq 等功能,那么使用泛型还意味着您的代码将更加简单且易于使用。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top