不要問我如何到達那裏,但我正在玩一些掩蔽,循環展開等等。無論如何,出於興趣,我正在考慮如何實現indexof方法,並且長話短說,所有這些掩蓋等,這個幼稚的執行:爲什麼我的string.indexof(char)更快?
public static unsafe int IndexOf16(string s, int startIndex, char c) {
if (startIndex < 0 || startIndex >= s.Length) throw new ArgumentOutOfRangeException("startIndex");
fixed (char* cs = s) {
for (int i = startIndex; i < s.Length; i++) {
if ((cs[i]) == c) return i;
}
return -1;
}
}
比string.IndexOf(char)更快。我寫了一些簡單的測試,它似乎完全匹配輸出。 從我的機器的一些樣本輸出號(它變化到一定程度,當然,但趨勢是明確的):
short haystack 500k runs
1741 ms for IndexOf16
2737 ms for IndexOf32
2963 ms for IndexOf64
2337 ms for string.IndexOf <-- buildin
longer haystack:
2888 ms for IndexOf16
3028 ms for IndexOf32
2816 ms for IndexOf64
3353 ms for string.IndexOf <-- buildin
IndexOfChar被標記的extern,所以你不能反射器吧。但我認爲這應該是(本地)執行: http://www.koders.com/cpp/fidAB4768BA4DF45482A7A2AA6F39DE9C272B25B8FE.aspx?s=IndexOfChar#L1000
他們似乎使用相同的樸素的實現。
問題來到我的腦海:
1)我失去了我在執行的東西,解釋了爲什麼它的速度更快?我只能想到擴展字符的支持,但是他們的實現表明他們沒有爲此做任何特別的事情。
2)我認爲大部分低級方法最終都會在手工彙編中實現,看起來並非如此。如果是這樣,爲什麼在本地執行它,而不是像在我的示例實現中一樣在C#中實現?
(這裏完整的測試(我認爲它太長時間貼在這裏):http://paste2.org/p/1606018)
(不,這不是過早的優化,它不是一個項目,我只是搞亂):-)
更新:Thnx to Oliver提示關於nullcheck和Count參數。我已經添加了這些我IndexOf16Implementation像這樣:
public static unsafe int IndexOf16(string s, int startIndex, char c, int count = -1) {
if (s == null) throw new ArgumentNullException("s");
if (startIndex < 0 || startIndex >= s.Length) throw new ArgumentOutOfRangeException("startIndex");
if (count == -1) count = s.Length - startIndex;
if (count < 0 || count > s.Length - startIndex) throw new ArgumentOutOfRangeException("count");
int endIndex = startIndex + count;
fixed (char* cs = s) {
for (int i = startIndex; i < endIndex; i++) {
if ((cs[i]) == c) return i;
}
return -1;
}
}
的數字略有變化,但它仍然是相當快顯著(32/64結果略):
short haystack 500k runs
1908 ms for IndexOf16
2361 ms for string.IndexOf
longer haystack:
3061 ms for IndexOf16
3391 ms for string.IndexOf
UPDATE2:此版本是更快的,但(特別是對於長草堆情況下):
public static unsafe int IndexOf16(string s, int startIndex, char c, int count = -1) {
if (s == null) throw new ArgumentNullException("s");
if (startIndex < 0 || startIndex >= s.Length) throw new ArgumentOutOfRangeException("startIndex");
if (count == -1) count = s.Length - startIndex;
if (count < 0 || count > s.Length - startIndex) throw new ArgumentOutOfRangeException("count");
int endIndex = startIndex + count;
fixed (char* cs = s) {
char* cp = cs + startIndex;
for (int i = startIndex; i <= endIndex; i++, cp++) {
if (*cp == c) return i;
}
return -1;
}
}
更新4: 基於與LastCoder的討論,我認爲這是依賴於架構。我的Xeon W3550似乎更喜歡這個版本,而他的i7似乎更喜歡buildin版本。我的家用機器(Athlon II)似乎介於兩者之間。儘管如此,我感到驚訝。
mask1應該是0xffff而不是0xff – hazzik
@hazzik thnx爲提示 – chrisaut