Почему функция isprefix быстрее, чем Startswith в C #?

Кто-нибудь знает, почему C # (.NET) начинается с работает значительно медленнее, чем IsPrefix?


person Community    schedule 04.04.2009    source источник


Ответы (4)


Я думаю, что это в основном получение текущей культуры потока.

Если вы измените тест Марка на использование этой формы String.StartsWith:

    Stopwatch watch = Stopwatch.StartNew();
    CultureInfo cc = CultureInfo.CurrentCulture;
    for (int i = 0; i < LOOP; i++)
    {
        if (s1.StartsWith(s2, false, cc)) chk++;
    }
    watch.Stop();
    Console.WriteLine(watch.ElapsedMilliseconds + "ms; chk: " + chk);

это намного ближе.

Если вы используете s1.StartsWith(s2, StringComparison.Ordinal), это намного быстрее, чем CompareInfo.IsPrefix (конечно, в зависимости от CompareInfo). На моем ящике результаты (не с научной точки зрения):

  • s1.StartsWith (s2): 6914 мс
  • s1.StartsWith (s2, false, culture): 5568 мс
  • сравнить.IsPrefix (s1, s2): 5200 мс
  • s1.StartsWith (s2, StringComparison.Ordinal): 1393 мс

Очевидно, это потому, что на самом деле это просто сравнение 16-битных целых чисел в каждой точке, что довольно дешево. Если вам не нужна проверка с учетом языка и региональных параметров, производительность и особенно важна для вас, я бы использовал эту перегрузку.

person Jon Skeet    schedule 04.04.2009

Хороший вопрос; для теста я получаю:

9156ms; chk: 50000000
6887ms; chk: 50000000

Испытательный стенд:

using System;
using System.Diagnostics;
using System.Globalization;    

class Program
{
    static void Main()
    {
        string s1 = "abcdefghijklmnopqrstuvwxyz", s2 = "abcdefg";

        const int LOOP = 50000000;
        int chk = 0;
        Stopwatch watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            if (s1.StartsWith(s2)) chk++;
        }
        watch.Stop();
        Console.WriteLine(watch.ElapsedMilliseconds + "ms; chk: " + chk);

        chk = 0;
        watch = Stopwatch.StartNew();

        CompareInfo ci = CultureInfo.CurrentCulture.CompareInfo;
        for (int i = 0; i < LOOP; i++)
        {
            if (ci.IsPrefix(s1, s2)) chk++;
        }
        watch.Stop();
        Console.WriteLine(watch.ElapsedMilliseconds + "ms; chk: " + chk);
    }
}
person Marc Gravell    schedule 04.04.2009

StartsWith вызывает внутренний вызов IsPrefix. Он назначает информацию о культуре перед вызовом IsPrefix.

person dommer    schedule 04.04.2009

Проверьте источник IsPrefix. Дело в том, что в некоторых случаях он будет медленнее, чем StartsWith, просто потому, что на самом деле использует StartsWith и выполняет несколько дополнительных операций.

    [System.Security.SecuritySafeCritical]  // auto-generated
    public unsafe virtual bool IsPrefix(String source, String prefix, CompareOptions options)
    { 
        if (source == null || prefix == null) {
            throw new ArgumentNullException((source == null ? "source" : "prefix"), 
                Environment.GetResourceString("ArgumentNull_String")); 
        }
        Contract.EndContractBlock(); 
        int prefixLen = prefix.Length;

        if (prefixLen == 0)
        { 
            return (true);
        } 

        if (options == CompareOptions.OrdinalIgnoreCase)
        { 
            return source.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
        }

        if (options == CompareOptions.Ordinal) 
        {
            return source.StartsWith(prefix, StringComparison.Ordinal); 
        } 

        if ((options & ValidIndexMaskOffFlags) != 0) { 
            throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"), "options");
        }


        // to let the sorting DLL do the call optimization in case of Ascii strings, we check if the strings are in Ascii and then send the flag RESERVED_FIND_ASCII_STRING  to
        // the sorting DLL API SortFindString so sorting DLL don't have to check if the string is Ascii with every call to SortFindString. 

        return (InternalFindNLSStringEx(
                    m_dataHandle, m_handleOrigin, m_sortName, 
                    GetNativeCompareFlags(options) | Win32Native.FIND_STARTSWITH | ((source.IsAscii() && prefix.IsAscii()) ? RESERVED_FIND_ASCII_STRING : 0),
                    source, source.Length, 0, prefix, prefix.Length) > -1);
    }
person Arsen Zahray    schedule 22.06.2013