我有一项任务需要在文件中查找序列。在进行测试应用程序时,我已将文件读取为字符串 (File.ReadAllText) 并使用 string.IndexOf 查找序列。当我尝试用字节实现相同的算法(将文件作为字节数组读取并在字节数组中查找字节数组)时,我注意到在字节[]中查找字节[]的速度大约是在字符串中查找字符串的速度的 3 倍. 我确保彻底检查它,并且完全相同的代码,一个使用字节 [] 和另一个使用字符串,执行时间是 3 倍 - 例如,字节 16 秒与字符串约 5 秒。
为了查找字节数组,我使用了此处描述的方法byte[] array pattern search。为了查找字符串,我使用了字符串类的内置 IndexOf 函数。这是我尝试过的 byte[] 的 IndexOf 实现之一:
public int IndexOf(byte[] source, byte[] pattern, int startpos = 0)
{
int search_limit = source.Length - pattern.Length;
for (int i = startpos; i < search_limit; i++)
{
if (source[i] == pattern[0])
{
bool found = true;
for (int j = 1; j < pattern.Length; j++)
{
if (source[i + j] != pattern[j])
{
found = false;
break;
}
}
if (found)
return i;
}
}
return -1;
}
基本上,查找字节数组中字节序列的下一个匹配项所花费的时间是查找字符串中字符序列的下一个匹配项的三倍。我的问题是——为什么?
有谁知道.Net如何处理查找字符串中的字符,它做了什么样的优化,它使用了什么算法?有没有比我在这里使用的更快的算法?也许有人知道我在这里做错了什么,所以它需要更多的时间?我真的不明白如何在字符串中查找字符串的速度是在 byte[] 中查找 byte[] 的 3 倍...
更新:我已经按照建议尝试了不安全的算法。情况如下:
public static unsafe long IndexOfFast(byte[] Haystack, byte[] Needle, long startpos = 0)
{
long i = startpos;
fixed (byte* H = Haystack) fixed (byte* N = Needle)
{
for (byte* hNext = H + startpos, hEnd = H + Haystack.LongLength; hNext < hEnd; i++, hNext++)
{
bool Found = true;
for (byte* hInc = hNext, nInc = N, nEnd = N + Needle.LongLength; Found && nInc < nEnd; Found = *nInc == *hInc, nInc++, hInc++) ;
if (Found) return i;
}
return -1;
}
}
}
奇怪的是,它实际上被证明是慢了一倍!我对其进行了更改以添加我的个人调整(在尝试迭代针之前检查第一个字母),现在看起来像这样:
public static unsafe long IndexOfFast(byte[] Haystack, byte[] Needle, long startpos = 0)
{
long i = startpos;
fixed (byte* H = Haystack) fixed (byte* N = Needle)
{
for (byte* hNext = H + startpos, hEnd = H + Haystack.LongLength; hNext < hEnd; i++, hNext++)
{
if (*hNext == *N)
{
bool Found = true;
for (byte* hInc = hNext+1, nInc = N+1, nEnd = N + Needle.LongLength; Found && nInc < nEnd; Found = *nInc == *hInc, nInc++, hInc++) ;
if (Found) return i;
}
}
return -1;
}
}
现在,它的执行时间与安全的执行时间完全相同。我的问题又是 - 任何想法为什么?与安全相比,它不应该更快,因为它不安全并且使用指针操作吗?