Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net String.IndexOf(char)真的比手动搜索慢吗?_.net_Performance_String - Fatal编程技术网

.net String.IndexOf(char)真的比手动搜索慢吗?

.net String.IndexOf(char)真的比手动搜索慢吗?,.net,performance,string,.net,Performance,String,在做一个简单的性能度量时,我惊讶地发现调用String.IndexOf(char)实际上比手动执行要慢!这是真的吗?!以下是我的测试代码: const string str = @"91023m lkajsdfl;jkasdf;piou-09324\\adf \asdf\45\ 65u\ 86\ 8\\\;"; static int testIndexOf() { return str.IndexOf('\\'); } static int testManualIndexOf() { s

在做一个简单的性能度量时,我惊讶地发现调用
String.IndexOf(char)
实际上比手动执行要慢!这是真的吗?!以下是我的测试代码:

const string str = @"91023m lkajsdfl;jkasdf;piou-09324\\adf \asdf\45\ 65u\ 86\ 8\\\;";
static int testIndexOf() { return str.IndexOf('\\'); }
static int testManualIndexOf() {
    string s = str;
    for (int i = 0; i < s.Length; ++i)
        if (s[i] == '\\') return i;
    return -1;
}
我至少运行了20次这些测试,每次都得到几乎相同的结果。我的机器是XP SP3,VS 2008 SP1,P4 3.0 GHz,没有超线程和1 GB RAM。我觉得结果真的很奇怪。如您所见,
String.IndexOf
比我的
PublicIndexOf
慢33%。更奇怪的是,我编写了与
内部
相同的方法,它比
公共
方法慢了大约8%!我不明白发生了什么,我希望你能帮助我理解

下面是测试代码。(很抱歉重复了代码,但我发现使用委托显示了不同的计时,而
public
internal
方法占用了相同的时间。)

公共静态类MyString{
public static int PublicIndexOf(字符串str,字符值){
对于(int i=0;i=str.Length)
抛出新ArgumentOutOfRangeException(“startIndex”);
对于(;startIndex=str.Length)
抛出新ArgumentOutOfRangeException(“startIndex”);
对于(;startIndex
下载.net framework的代码,看看str.IndexOf的真正功能,难道不可能吗

这个特定搜索的时间真的很关键,还是你在做致命的“无缘无故优化”?你试过用短的和长的弦吗?使用不同的搜索字符串?内置功能可能会针对其他情况进行优化,在这些情况下,搜索速度可能会较慢,而您的特定情况最终会较慢。我不会谴责IndexOf API“总是比较慢”,除非我对更多的情况做了更多的测试。

即使它“手动”做得更快,也不明智。在你的.net版本中,你的CLR设置可能会更快。大概至少对于那个特定的字符串。但是你可以非常肯定的是,随着时间的推移,内置软件会有更好的改进机会。用你的语言。IndexOf也更加清晰。

也许这25%是调用函数的成本


您的方法(testManualIndexOf)不调用任何函数。

首先,您会有额外的函数调用开销。您是否尝试过将手动搜索包装在一个方法中并从测试中调用它——这确实是最好的比较,因为您不太可能每次都希望在字符串中搜索字符时编写该循环。

您的测试并不公平,因为您没有实现相同的功能:

  • 您没有向手动测试传递任何参数,而是使用const引用,与在real
    IndexOf
    方法中传递参数时相比,需要执行的操作代码更少
  • 您的
    IndexOf
    测试实际上进行了两次方法调用,而不是一次。很可能外部方法调用将内联到未在调试器下运行的发布版本中,但您的测试没有指明运行它的条件(如果是这种情况,那么您可以忽略这一点)

  • 但从本质上讲,考虑到您的方法所做的工作较少,我并不奇怪它运行得更快。

    正如前面所说的,我认为函数调用可能会导致一些问题
      -   String.      IndexOf : 00:00:07.6490042
      - MyString.PublicIndexOf : 00:00:05.6676471
      - MyString.InternIndexOf : 00:00:06.1191796
      - MyString.PublicIndexOf2: 00:00:09.1363687
      - MyString.InternIndexOf2: 00:00:09.1182569
    
    public static class MyString {
        public static int PublicIndexOf(string str, char value) {
            for (int i = 0; i < str.Length; ++i)
                if (str[i] == value) return i;
            return -1;
        }
    
        internal static int InternIndexOf(string str, char value) {
            for (int i = 0; i < str.Length; ++i)
                if (str[i] == value) return i;
            return -1;
        }
    
        public static int PublicIndexOf2(string str, char value, int startIndex) {
            if (startIndex < 0 || startIndex >= str.Length)
                throw new ArgumentOutOfRangeException("startIndex");
            for (; startIndex < str.Length; ++startIndex)
                if (str[startIndex] == value) return startIndex;
            return -1;
        }
    
        internal static int InternIndexOf2(string str, char value, int startIndex) {
            if (startIndex < 0 || startIndex >= str.Length)
                throw new ArgumentOutOfRangeException("startIndex");
            for (; startIndex < str.Length; ++startIndex)
                if (str[startIndex] == value) return startIndex;
            return -1;
        }
    }
    
    class Program {
        static void Main(string[] args) {
            int iterations = 100 * 1000 * 1000; // 100 millions
            char separator = '\\';
            string str = @"91023m lkajsdfl;jkasdf;piou-09324\\adf \asdf\45\ 65u\ 86\ 8\\\;";
            Stopwatch watch = new Stopwatch();
    
            // test String.IndexOf
            int sum = 0;
            watch.Start();
            for (int i = 0; i < iterations; ++i)
                sum += str.IndexOf(separator);
            watch.Stop();
            Console.WriteLine("  String.      IndexOf : ({0}, {1})", watch.Elapsed, sum);
    
            // test MyString.PublicIndexOf
            sum = 0;
            watch.Reset(); watch.Start();
            for (int i = 0; i < iterations; ++i)
                sum += MyString.PublicIndexOf(str, separator);
            watch.Stop();
            Console.WriteLine("MyString.PublicIndexOf : ({0}, {1})", watch.Elapsed, sum);
    
            // test MyString.InternIndexOf
            sum = 0;
            watch.Reset(); watch.Start();
            for (int i = 0; i < iterations; ++i)
                sum += MyString.InternIndexOf(str, separator);
            watch.Stop();
            Console.WriteLine("MyString.InternIndexOf : ({0}, {1})", watch.Elapsed, sum);
    
            // test MyString.PublicIndexOf2
            sum = 0;
            watch.Reset(); watch.Start();
            for (int i = 0; i < iterations; ++i)
                sum += MyString.PublicIndexOf2(str, separator,0);
            watch.Stop();
            Console.WriteLine("MyString.PublicIndexOf2: ({0}, {1})", watch.Elapsed, sum);
    
            // test MyString.InternIndexOf2
            sum = 0;
            watch.Reset(); watch.Start();
            for (int i = 0; i < iterations; ++i)
                sum += MyString.InternIndexOf2(str, separator,0);
            watch.Stop();
            Console.WriteLine("MyString.InternIndexOf2: ({0}, {1})", watch.Elapsed, sum);
        }
    }
    
        static void Main(string[] args)
        {
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                for (int i = 0; i < 25000000; i++)
                    testIndexOf();
                sw.Stop();
                Console.WriteLine(sw.Elapsed); //2.27 s
            }
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                for (int i = 0; i < 25000000; i++)
                    testManualIndexOf();
                sw.Stop();
                Console.WriteLine(sw.Elapsed); //9.81 s
            }
    
            Console.ReadLine();
        }
    
    String.      IndexOf : (00:00:06.3134669, -994967296)
    MyString.PublicIndexOf : (00:00:07.0769368, -994967296)
    MyString.InternIndexOf : (00:00:08.3463652, -994967296)
    MyString.PublicIndexOf2: (00:00:12.0049268, -994967296)
    MyString.InternIndexOf2: (00:00:12.4344756, -994967296)
    
    static void Main()
    {
        const int LOOP = 25000000;
        int chk1 = 0, chk2 = 0;
        Stopwatch watch1 = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            chk1 += testIndexOf();
        }
        watch1.Stop();
        Stopwatch watch2 = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            chk2 += testManualIndexOf();
        }
        watch2.Stop();
    
        Console.WriteLine("{0}ms, ({1})", watch1.ElapsedMilliseconds, chk1);
        Console.WriteLine("{0}ms, ({1})", watch2.ElapsedMilliseconds, chk2);
    
    }
    
    public static void Main(string[] args) {
        int nTrials = 10000000;
        Random rg = new Random(1);
        Stopwatch sw = new Stopwatch();
        for (int i = 0; i < nTrials; i++) {
            int len = 1 + rg.Next(250);
            char[] randomChar = new char[len];
            for(int j = 0; j < len; j++) {
                randomChar[j] = GetRandomLetterOrDigit(rg);
            }
            string s = new string(randomChar);
            char findChar = GetRandomLetterOrDigit(rg);
            sw.Start();
            int index = s.IndexOf(findChar);
            //int index = testManualIndexOf(s, findChar);
            sw.Stop();
        }
        Console.WriteLine(sw.ElapsedMilliseconds);
    }
    
    private static char GetRandomLetterOrDigit(Random rg) {
        char c;
        int rc = rg.Next(62);
    
        if (rc < 26) {
            c = (char)('A' + rc);
        }
        else if (rc < 52) {
            c = (char)('a' + rc - 26);
        }
        else {
            c = (char)('0' + rc - 52);
        }
        return c;
    }
    
    private static int testManualIndexOf(string s, char c) {
        if (s == null) {
            throw new ArgumentNullException("s");
        }
        for (int i = 0; i < s.Length; ++i) {
            if (s[i] == c) return i;
        }
        return -1;
    }