待辦事項es .net對每個使用的字符串都使用字符串實習生?
不,但它確實將它用於編譯時知道的那些字符串,因爲它們是代碼中的常量。
string x = "abc"; //interned
string y = "ab" + "c"; //interned as the same string because the
//compiler can work out that it's the same as
//y = "abc" at compile time so there's no need
//to do that concatenation at run-time. There's
//also no need for "ab" or "c" to exist in your
//compiled application at all.
string z = new StreamReader(new FileStream(@"C:\myfile.text")).ReadToEnd();
//z isn't interned because it isn't known at compile
//time. Note that @"C:\myfile.text" is interned because
//while we don't have a variable we can access it by
//it is a string in the code.
如果是這樣,是不是傷害的表現?
不,這有助於提高性能:
第一:所有這些字符串將要在應用程序的內存某處。實習意味着 我們沒有不必要的副本,所以我們使用較少的內存。其次:它使得我們所知道的字符串比較來自只是超快的字符串。第三:這並沒有多大提升,但是其他比較的提升確實如此。考慮一下內置比較器中存在的代碼:
public override int Compare(string x, string y)
{
if (object.ReferenceEquals(x, y))
{
return 0;
}
if (x == null)
{
return -1;
}
if (y == null)
{
return 1;
}
return this._compareInfo.Compare(x, y, this._ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
}
這是爲了排序,但同樣適用於等式/不等式檢查。要檢查兩個字符串是否相等,或者要求它們按順序排列,需要我們執行O(n)操作,其中n與字符串的長度成比例(即使在可以完成一些跳過和聰明操作的情況下,它仍然是成比例的) 。對於長字符串,這可能會很慢,並且比較字符串是很多應用程序在很多情況下都會執行的操作 - 這是提高速度的好地方。這對於平等情況來說也是最慢的(因爲我們發現差異的時候我們可以返回一個值,但是必須完全檢查相同的字符串)。
即使您重新定義「等於」意味着什麼(區分大小寫,不區分大小寫,不同文化 - 一切仍然等於本身,並且如果您創建了不符合要求的覆蓋範圍,有一個錯誤)。所有東西總是以相同的點排列。這意味着兩件事:
- 我們總是可以考慮與自己相同的東西,而無需做任何更多的工作。
- 我們總是可以給出一個比較值
0
,用於比較某件事情和沒有任何工作。
因此上述上這種情況下捷徑的代碼,而無需做更復雜和昂貴的比較。也沒有下跌,因爲如果我們不覆蓋這種情況下,我們必須添加一個測試,以便兩個值均通過null
。
現在,碰巧某些算法的工作方式自然而然地比較了一些東西,所以它總是值得去做。但是,字符串實習會增加兩個字符串的時間差異(例如,在問題開始時的x
和z
)實際上是相同的,所以它會增加快捷方式對我們的工作頻率。
大多數時候這是一個很小的優化,但是我們可以免費獲得它,我們經常得到它,擁有它是非常棒的。從這個實用的東西 - 如果你正在寫Equals
或Compare
考慮你是否也應該使用這個捷徑。
那麼一個相關的問題是「我應該實習一切嗎?」我們不得不考慮編譯字符串沒有的缺點。實習並不浪費編譯字符串,因爲他們必須在某個地方。但是,如果你從文件中讀取一個字符串,實施它,然後再也不用它,它將會持續很長時間,這是浪費。如果你一直這樣做,你可能會削弱你的記憶力。
讓我們想象一下,您經常閱讀一堆包含某些標識符的項目。您經常使用這些標識符將項目與其他來源的數據進行匹配。有一小部分標識符可以看到(比如只有幾百個可能的值)。然後,因爲平等檢查是這些字符串的全部內容,並且沒有太多實際情況,因此實習(在讀入的數據和您與之比較的數據 - 其他方面都沒有意義)將成爲一場勝利。
或者,假設有幾千個這樣的對象,我們匹配它的數據總是被緩存在內存中 - 這意味着這些字符串總是會在內存中的任何地方,所以實習成爲一個無需思考的工具贏得。 (除非有很多「未找到」結果的可能性 - 實習這些標識符只是爲了找不到匹配就是輸)。
最後,相同的基本技術可以做不同的處理。例如XmlReader
存儲字符串,它在NameTable
中比較的行爲類似於私人實習生池,但可以在完成時收集整個事情。您也可以將該技術應用於任何參考類型,這些參考類型在合併時不會更改(保證不變的最佳方法是使其不變,以便在任何時候都不會更改)。將這種技術用於具有大量重複的非常大的集合可以大量減少內存使用(我的最大節省至少爲16GB--它可能更多,但服務器在應用該技術之前在該點附近保持崩潰)和/或速度比較。
對[字符串實習生]很好的閱讀(http://blogs.msdn.com/b/ericlippert/archive/2009/09/28/string-interning-and-string-empty.aspx) – V4Vendetta 2012-08-17 10:27:17