C# 查找字节[]中的字节[]和字符串中的字符串的速度-为什么后者更快?

C# 查找字节[]中的字节[]和字符串中的字符串的速度-为什么后者更快?,c#,string,search,byte,bytearray,C#,String,Search,Byte,Bytearray,我有一个任务,需要在文件中查找序列。在执行测试应用程序时,我将文件读取为string(file.ReadAllText),并使用string.IndexOf查找序列。当我尝试用字节实现相同的算法(以字节数组的形式读取文件并在字节数组中查找字节数组)时,我注意到在字节[]中查找字节[]的速度大约是在字符串中查找字符串的速度的3倍。我确保彻底检查它,完全相同的代码,一个使用byte[],另一个使用string,执行所需的时间是原来的3倍——比如,字节为16s,字符串为5s 为了查找字节数组,我使用了

我有一个任务,需要在文件中查找序列。在执行测试应用程序时,我将文件读取为string(file.ReadAllText),并使用string.IndexOf查找序列。当我尝试用字节实现相同的算法(以字节数组的形式读取文件并在字节数组中查找字节数组)时,我注意到在字节[]中查找字节[]的速度大约是在字符串中查找字符串的速度的3倍。我确保彻底检查它,完全相同的代码,一个使用byte[],另一个使用string,执行所需的时间是原来的3倍——比如,字节为16s,字符串为5s

为了查找字节数组,我使用了这里描述的方法。为了查找字符串,我使用了string类的内置IndexOf函数。下面是我尝试过的字节[]的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;
    }
public int IndexOf(字节[]源,字节[]模式,int startpos=0)
{
int search_limit=source.Length-pattern.Length;
对于(int i=startpos;i
基本上,查找字节数组中字节序列的下一个匹配项所需的时间是查找字符串中字符序列的下一个匹配项所需时间的三倍。我的问题是——为什么

有人知道.Net如何处理查找字符串中的字符,它做了什么样的优化,使用了什么算法吗?有没有比我现在使用的更快的算法?也许有人知道我做错了什么,所以要花更多的时间?我真的不明白在字符串中查找字符串的速度是在字节[]中查找字节[]的速度的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 indexofast(字节[]Haystack,字节[]Needle,long startpos=0)
{
长i=startpos;
固定(字节*H=草堆)固定(字节*N=针)
{
对于(字节*hNext=H+startpos,hEnd=H+Haystack.longlegth;hNext
奇怪的是,事实证明它的速度是原来的两倍!我将其更改为添加我的个人调整(在尝试遍历针之前检查第一个字母),现在看起来如下所示:

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;
        }
    }
public static unsafe long indexofast(字节[]Haystack,字节[]Needle,long startpos=0)
{
长i=startpos;
固定(字节*H=草堆)固定(字节*N=针)
{
对于(字节*hNext=H+startpos,hEnd=H+Haystack.longlegth;hNext

现在,它的执行时间与安全的执行时间完全相同。我的问题是——你知道为什么吗?与安全相比,它是否应该更快一些,因为它不安全,并且使用指针操作?

您的字节搜索算法效率极低

比较所有其他字符串搜索的基线算法是。我敢打赌.NET字符串搜索使用它或它的变体。也有,但实现Boyer Moore for bytes将为您提供更好的性能

编辑:那就去营救吧

使用计时编号编辑: Eric的评论让我非常感兴趣,因为我一直听说.Net字符串搜索使用Boyer Moore。我真的很感激有人告诉我其他的事情。经过思考,这是完全有道理的。我决定对Boyer Moore vs Naive byte搜索进行计时,结果发现Eric对于小针和小草堆来说绝对正确Naive搜索速度快了13倍以上。但令我惊讶的是,“收支平衡”点远低于我的预期。Boyer Moore在模式大小(或我计时中的针大小)方面有显著改进,因此您要查找的模式越大,搜索速度就越快。对于8字节的针头搜索,朴素的搜索与博耶·摩尔的搜索在500-600字节的草堆中平分秋色。对于更大的干草堆,Boyer Moore会变得更好,尤其是使用更大的针。对于20KB的草堆和64字节的针,Boyer Moore的速度快了10倍

下面是所有感兴趣的人的完整时间数字

所有测试都使用了上面链接的简单的Boyer Moore和Op发布的朴素字节搜索算法,进行了1M次搜索迭代

1000000 iterations, haystack size = 20 bytes, needle size = 8 bytes
20ms total : Naive Search
268ms total : Boyer-Moore Search

1000000 iterations, haystack size = 600 bytes, needle size = 8 bytes
608ms total : Naive Search
582ms total : Boyer-Moore Search

1000000 iterations, haystack size = 2000 bytes, needle size = 8 bytes
2011ms total : Naive Search
1339ms total : Boyer-Moore Search

1000000 iterations, haystack size = 2000 bytes, needle size = 32 bytes
1865ms total : Naive Search
563ms total : Boyer-Moore Search

1000000 iterations, haystack size = 2000 bytes, needle size = 64 bytes
1883ms total : Naive Search
466ms total : Boyer-Moore Search

1000000 iterations, haystack size = 20000 bytes, needle size = 8 bytes
18899ms total : Naive Search
10753ms total : Boyer-Moore Search

1000000 iterations, haystack size = 20000 bytes, needle size = 32 bytes
18639ms total : Naive Search
3114ms total : Boyer-Moore Search

1000000 iterations, haystack size = 20000 bytes, needle size = 64 bytes
18866ms total : Naive Search
1807ms total : Boyer-Moore Search
基本上,查找字节数组中字节序列的下一个匹配项所需的时间是查找字符串中字符序列的下一个匹配项所需时间的三倍。我的问题是——为什么

因为字符串搜索算法已经过大量优化;它是用紧凑的非托管代码编写的,不需要花时间检查数组边界。如果你用同样的方法优化你的字节搜索算法,它会同样快;字符串搜索算法使用与您使用的相同的朴素算法

你的算法很好