【问题标题】:Do you choose Linq over Forloops?你选择 Linq 而不是 For 循环?
【发布时间】:2010-07-26 11:00:09
【问题描述】:

给定一个包含两列的数据表,如下所示:

Private Function CreateDataTable() As DataTable
    Dim customerTable As New DataTable("Customers")
    customerTable.Columns.Add(New DataColumn("Id", GetType(System.Int32)))
    customerTable.Columns.Add(New DataColumn("Name", GetType(System.String)))

    Dim row1 = customerTable.NewRow()
    row1.Item("Id") = 1
    row1.Item("Name") = "Customer 1"
    customerTable.Rows.Add(row1)

    Dim row2 = customerTable.NewRow()
    row2.Item("Id") = 2
    row2.Item("Name") = "Customer 2"
    customerTable.Rows.Add(row2)

    Dim row3 = customerTable.NewRow()
    row3.Item("Id") = 3
    row3.Item("Name") = "Customer 3"
    customerTable.Rows.Add(row3)

    Return customerTable
End Function

你会使用这个 sn-p 来检索包含所有 Id 的 List(Of Integer):

Dim table = CreateDataTable()

Dim list1 As New List(Of Integer)

For i As Integer = 0 To table.Rows.Count - 1
    list1.Add(CType(table.Rows(i)("Id"), Integer))
Next

或者更确切地说是这个:

Dim list2 = (From r In table.AsEnumerable _
             Select r.Field(Of Integer)("Id")).ToList()

这不是关于是否使用 .Field(Of Integer)、CType、CInt、DirectCast 或其他任何方式将 Id 列类型转换为 Integer 的问题,而是关于您是否像主题暗示的那样选择 Linq 而不是 forloops。


对于那些感兴趣的人:我对这两个版本都进行了一些迭代,结果得到了以下性能图表:

graph http://dnlmpq.blu.livefilestore.com/y1pOeqhqQ5neNRMs8YpLRlb_l8IS_sQYswJkg17q8i1K3SjTjgsE4O97Re_idshf2BxhpGdgHTD2aWNKjyVKWrQmB0J1FffQoWh/analysis.png?psid=1

纵轴显示代码将行 ID 转换为通用列表所需的毫秒数,横轴显示行数。蓝线来自命令式方法(forloop),红线来自声明性代码(linq)。


无论您通常选择哪种方式:为什么您选择那条路而不是另一条路?

【问题讨论】:

    标签: vb.net linq for-loop


    【解决方案1】:

    只要有可能,我更喜欢声明式的编程方式而不是命令式的编程方式。当您使用声明性方法时,CLR 可以根据机器的特性优化代码。例如,如果它有多个内核,它可以并行执行,而如果您使用命令式 for 循环,则基本上锁定了这种可能性。今天也许没有什么大的不同,但我认为未来会出现越来越多的扩展,比如 PLINQ,从而实现更好的优化。

    【讨论】:

    • 真的是这样吗?我想起了前段时间读过的一篇博客文章。你可以在这里找到它:ox.no/posts/linq-vs-loop-a-performance-test。基本结论是这样的:“自然,这不会像传统的命令式循环那样好,并且可以进行的优化更少”。此结果来自运行时比较,该结果导致 linq 查询的性能比命令式方法差 50 倍。
    • 我发现关于性能的论据不是一个很好的论据,而且我认为您永远不必期望 LINQ 查询的性能在没有任何代码更改的情况下大幅提高,因为系统必须向后兼容。但是,由于可读性和可维护性,我更喜欢声明式编程方式。 LINQ 查询在表达意图方面要好得多。
    • 我支持这个。我也认为声明式 linq 查询更具可读性,因此更易于维护。但是,Darin 引入了代码优化的论点,我想知道编译器是否真的能够基于声明式语法比命令式代码更好地优化代码。
    • @Darin:你有没有在 Reflector 中打开过 Linq 查询? LINQ 实际上并未在生成的 Linq to Objects 二进制文件中发出。
    • @Billy,是的,我在 Reflector 中打开了一个 LINQ 查询。它基于被调用的扩展方法,所以我不明白你关于 LINQ 没有在生成的二进制文件中发出的论点。
    【解决方案2】:

    除非它对可读性有很大帮助,否则我会避免使用 linq,因为它完全破坏了编辑并继续。

    当他们解决这个问题时,我可能会开始更多地使用它,因为我确实非常喜欢某些事情的语法。

    【讨论】:

    • 您对将调试器与 LINQ 一起使用做出了公平的陈述。但是,我喜欢扭转它:除非我必须调试该代码,否则我会使用 LINQ。在那种情况下,我(暂时)重写了那句话。但是,通常情况下,单元测试可以节省我的时间。
    【解决方案3】:

    对于我所做的几乎所有事情,我得出的结论是 LINQ 已足够优化。如果我手工制作一个 for 循环,它会有更好的性能,但在宏观上,我们通常说的是毫秒。由于我很少遇到这些毫秒会产生任何影响的情况,因此我发现拥有具有明确意图的可读代码更为重要。我宁愿有一个慢 50 毫秒的呼叫,也不愿有人过来完全中断它!

    【讨论】:

      【解决方案4】:

      Resharper 有一个很酷的功能,可以标记循环并将其转换为 Linq 表达式。我会将它翻转到 Linq 版本,看看这是否会伤害或有助于可读性。如果 Linq 表达式更清楚地传达代码的意图,我会同意的。如果 Linq 表达式不可读,我会翻回 foreach 版本。

      对我来说,大多数性能问题都无法与可读性相比。

      清晰胜过聪明。

      在上面的例子中,我会选择 Linq 版本,因为它清楚地解释了意图,并且还阻止了人们在循环中意外添加副作用。

      【讨论】:

      • 这正是我所做的。但是,由于我们已经有“百万”个地方使用循环并且这是每个人都习惯的,所以我保持原样。
      【解决方案5】:

      我最近发现自己想知道我是否完全被 LINQ 宠坏了。是的,我现在一直使用它从各种收藏中挑选各种东西。

      【讨论】:

        【解决方案6】:

        我开始这样做,但发现在某些情况下,我使用这种方法节省了时间:

        for (var i = 0, len = list.Count; i < len; i++) { .. }
        

        不一定在所有情况下,但在某些情况下。大多数扩展方法都使用 foreach 方法进行查询。

        【讨论】:

          【解决方案7】:

          我尽量遵守这些规则:

          • 只要我只是查询(过滤、投影……)集合,就使用 LINQ。
          • 一旦我真正对结果“做”某事(即引入副作用),我将使用 for 循环。

          所以在本例中,我将使用 LINQ。

          另外,我总是尝试将“查询定义”与“查询评估”分开:

          Dim query = From r In table.AsEnumerable() 
                      Select r.Field(Of Integer)("Id")
          
          Dim result = query.ToList()
          

          这清楚地表明何时评估(在本例中为内存中的)查询。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-12-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多