15

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

从性能的角度来看,更改代码对使用泛型有多重要?我知道从性能的角度来看,装箱和拆箱等,它是低效的,但是改变它真的会有多少性能提升呢?泛型是在前进的基础上使用的东西,还是有足够的性能变化需要良心努力来更新旧代码?

4

12 回答 12

14

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

我会建议:

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

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

  • 不易出错,因为您对类型进行了编译时检查
  • 更具可读性,您不需要到处进行强制转换,并且很明显集合中存储了什么类型
  • 如果您正在使用泛型,那么在任何地方都使用它们会更干净
于 2008-09-18T17:56:42.803 回答
8

这是我从 100KB 文件中简单解析字符串 100,000 次得到的结果。Generic List(Of char) 花了 612.293 秒来遍历文件 100,000 次。ArrayList 花了 2,880.415 秒来遍历文件 100,000 次。这意味着在这种情况下(因为您的里程有所不同)Generic List(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
于 2008-09-18T19:02:20.867 回答
4

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

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

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

于 2008-09-18T17:51:07.043 回答
3

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

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

于 2008-09-18T17:54:36.083 回答
1

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

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

编辑:Outlaw Programmer 有一个很好的观点,你仍然会用泛型装箱和拆箱,它只是隐含地发生。不过,所有关于从强制转换和“is/as”关键字检查异常和空值的代码都会有所帮助。

于 2008-09-18T17:53:54.713 回答
0

最大的收获是在维护阶段。泛型更容易处理和更新,而无需处理转换和转换问题。如果这是您不断访问的代码,那么一定要努力。如果这是多年未触及的代码,我真的不会打扰。

于 2008-09-18T17:52:44.997 回答
0

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

于 2008-09-18T17:54:02.043 回答
0

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

再说一次,如果你不是在为客户做某事,那就继续花时间重构吧。它将为您自己提高代码的可读性。

于 2008-09-18T17:54:34.977 回答
0

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

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

如果您在整个代码中使用了很多 ArrayLists 并且替换它们将是一个很大的麻烦(这可能会影响您的日程安排),那么您可以采用 if-you-touch-it-change-it 方法。

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

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

于 2008-09-18T17:57:57.557 回答
0

如果 ArrayLists 中的实体是 Object 类型,您会从不将它们转换为正确的类型中获得一点好处。如果它们是值类型(结构体或 Int32 之类的原语),那么装箱/拆箱过程会增加很多开销,并且泛型集合应该快得多。

这是有关该主题的 MSDN 文章

于 2008-09-18T17:59:34.027 回答
0

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

  1. 将 Arraylist 与值类型一起使用会导致装箱/拆箱,如果完成数百次,则比使用泛型列表要慢得多。

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

我在这里写过。

于 2008-09-20T07:30:07.463 回答
0

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

于 2009-01-22T04:37:19.947 回答