不要问我如何到达那里,但我正在玩一些掩蔽,循环展开等等。无论如何,出于兴趣,我正在考虑如何实现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