2010-07-26 51 views
2

給出一個包含兩列這樣的數據表:你選擇了Forloops嗎?

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 

你會使用這個片段檢索列表(整數),包含所有的Id:

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作爲主題的暗示。


對於那些有興趣誰:我跑了一些重複這兩個版本這就造成了以下性能圖:

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

縱軸表示它採取了代碼轉換的毫秒行的id變成一個通用列表,橫軸顯示行數。藍線來自命令式(forloop),即來自聲明式代碼(linq)的紅線。


不管你的方法一般選擇:你爲什麼走那條路,而不是其他?

回答

5

只要有可能,我傾向於使用聲明式的編程方式而不是命令式的方式。當您使用聲明式方法時,CLR可以根據機器的特性優化代碼。例如,如果它有多個內核,它可以並行執行,而如果你使用循環的命令,你基本上鎖定了這種可能性。今天也許沒有太大區別,但我認爲未來會有越來越多的擴展如PLINQ出現,以便更好地進行優化。

+0

這是真的嗎?我記得前一段我讀過的博客文章。你可以在這裏找到它:http://ox.no/posts/linq-vs-loop-a-performance-test。基本結論是這樣的:「自然,這不會像傳統的命令循環那樣好,而且優化也不太可能」。這個結果來自運行時比較,導致linq查詢執行比命令式方法差50倍。 – Mephisztoe 2010-07-26 12:13:10

+0

我發現性能的論點不是很好,我不認爲如果沒有任何代碼更改,LINQ查詢的性能將無法大幅提高,因爲系統必須向後兼容。但是,由於可讀性和可維護性,我傾向於使用聲明式編程方式。 LINQ查詢在表達意圖方面要好得多。 – Steven 2010-07-26 12:16:59

+0

我第二個這個。我也認爲聲明性linq查詢更具可讀性,因此可以維護。然而,達林引入了代碼優化的論點,我想知道編譯器是否真的能夠比命令式代碼更好地基於聲明式語法優化代碼。 – Mephisztoe 2010-07-26 12:19:38

0

我最近發現自己想知道我是否被LINQ完全寵壞了。是的,我現在一直用它來從各種收藏中挑選各種各樣的東西。

1

我避免了linq,除非它有助於可讀性很多,因爲它完全破壞了編輯和繼續。

當他們解決這個問題時,我可能會開始更多地使用它,因爲我對某些事情喜歡語法很多。在所有情況下

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

不一定,但一些:

+1

您對使用LINQ調試器做出了公正的聲明。但是,我喜歡將它轉向:我使用LINQ,除非我必須調試該代碼。在那種情況下,我(暫時)重寫那句話。然而通常情況下,單元測試可以節省我的一天 – Steven 2010-07-26 12:19:40

0

我開始的,但在某些情況下發現,我用這種方式節省了時間。大多數擴展方法使用foreach方法進行查詢。

1

對於我所做的幾乎所有事情,我已經得出結論,LINQ是足夠優化。如果我手工製作一個for循環,它會有更好的表現,但在宏偉的計劃中我們通常會說毫秒。由於我很少有這樣的情況,那些毫秒會產生任何影響,所以我發現具有明確意圖的可讀代碼更重要。我寧願有一個電話比有人過來並且完全打破它慢50ms!

1

Resharper有一個很酷的功能,可以將循環標記並轉換爲Linq表達式。我將把它翻轉到Linq版本,看看是否會傷害或幫助可讀性。如果Linq表達式更清楚地傳達了代碼的意圖,我會繼續這樣做。如果Linq表達式不可讀,我會翻回到foreach版本。

大多數性能問題與我的可讀性無法比較。

明淨勝過聰明。

在上面的例子中,我會選擇Linq版本,因爲它清楚地解釋了這個意圖,並且鎖定了人們在循環中意外添加副作用。

+0

這正是我所做的。但是,由於我們已經有了使用循環的「百萬」場所,而這正是每個人都習慣的地方,所以我將它保留下來。 – Greg 2010-07-26 13:56:42

0

我儘量遵守以下規則:

  • 每當我只是查詢(篩選,投影,...)的集合,使用LINQ。一旦我真的「做」了某些結果(即引入副作用),我將使用for循環。

所以在這個例子中,我將使用LINQ。

而且,我總是試圖在「查詢定義」從「查詢評估」分裂:

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

Dim result = query.ToList() 

這清楚時(在這種情況下,內存)的查詢進行評估。