2010-08-13 74 views
9

對字符串進行子串處理是一種非常常見的字符串處理操作,但是我聽說Java和.NET平臺之間在性能/實現方面可能會有相當大的差異。具體我聽說在Java中,java.lang.String報價常數時間操作爲substring,但在.NET中,System.String報價線性性能Substring.NET和Java之間的子串操作性能比較

這些是真的嗎?這可以在文檔/源代碼等確認嗎?該實現是特定的還是由語言和/或平臺指定的?每種方法的優缺點是什麼?一個人從一個平臺遷移到另一個平臺應該怎樣才能避免陷入任何性能缺陷?

+1

爲什麼不運行你自己的微型基準測試來測試這個?你能鏈接到說它有「糟糕」表現的來源嗎? – Oded 2010-08-13 06:57:39

+0

@Oded:來源是丹尼陳的評論在這裏http://stackoverflow.com/questions/3474254/how-to-make-a-first-letter-capital-in-c/3474263#3474263;老實說,如果'Substring'不是'O(1)'時空操作(比如Java),但是我會給他帶來疑問的好處,因爲我不知道.NET。 – polygenelubricants 2010-08-13 06:59:09

+1

這是什麼意思「不良行爲」?相對於什麼?例如,與C++相比,.NET也有不好的表現。因此,我們應該放棄.NET嗎? – 2010-08-13 07:07:35

回答

11

在.NET中,Substring是O(n),而不是Java的O(1)。這是因爲在.NET中,String對象包含所有實際字符數據本身 - 所以取一個子字符串涉及複製新子字符串中的所有數據。在Java中,substring只需創建一個引用原始char數組的新對象,並使用不同的起始索引和長度。

有每一種方法的優點和缺點:

  • .NET的方法具有更好的高速緩存一致性,造成更少的對象,並且避免了一個小串防止收集了非常大的char[]是垃圾的情況。我相信在某些情況下,它可以使內部非常簡單。
  • Java的方法使服用子非常有效的,而且很可能一些其它的操作也

有一個在我strings article更詳細一點。

至於避免性能陷阱的一般問題,我想我應該有一個罐裝答案准備好剪切和粘貼:確保你的體系結構是有效的,並以最可讀的方式實現它。衡量性能,並優化你發現瓶頸的地方。


順便說一句,這使得string很特別 - 它是唯一的非數組類型,其內存佔用由實例相同CLR內變化。

對於小字符串,這是一個很大的勝利。足夠糟糕的是,所有一個對象的開銷,但是當涉及額外的數組時,單字符字符串在Java中可能需要大約36個字節。 (這是一個「手指在空中」的數字 - 我不記得確切的目標開銷,它也將取決於你使用的虛擬機。)

2

使用反射,這是你的子串得到什麼(的Int32,Int32)將

[SecuritySafeCritical, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
public string Substring(int startIndex, int length) 
{ 
    return this.InternalSubStringWithChecks(startIndex, length, false); 
} 

,如果你繼續在最後一次通話中去,是一個

internal static unsafe void wstrcpy(char* dmem, char* smem, int charCount) 

使用指針複製字符。 完整的代碼實際上看起來很大,但你不會看到它有多快或多慢,直到你運行它並進行基準測試。

0

這真的取決於你的工作量。如果您正在循環並執行大量子字符串調用,那麼您可能會遇到問題。對於你所指的SO帖子,我懷疑它永遠是個問題。然而,用這種態度,你總是可以在「一千人的死亡裁員」的情況下結束。在SO張貼您參考,我們有以下幾點:

String after = before.Substring(0, 1).ToUpper() + before.Substring(1); 

假設編譯器不會做一些瘋狂的優化,這將創造至少四個新的字符串(2個Substring電話,一個電話ToUpper和級聯)。子串的實現與你期望的完全相同(字符串複製),但是上面分配的三個字符串很快就會變成垃圾。做這麼多事情會造成不必要的記憶壓力。我說「不必要」,因爲你可能會想出更經濟的解決方案,只需要多一點時間投資。

最後,分析器是你最好的朋友:)