Сравнение строк в каркасе dotnet 4 - PullRequest
6 голосов
/ 22 сентября 2010

Я объясню свою проблему (извините за плохой английский), у меня есть .NET exe, в котором каждая миллисекунда обработки очень важна.

Эта программа часто сравнивает строки (в большинстве случаев это string1.IndexOf(string2, StringComparison.OrdinalIgnoreCase)).

Когда я переключаюсь на фреймворк 4, время моей программы вдвое больше, чем раньше.

Я искал объяснение и обнаружил, что функция IndexOf(s, OrdinalIgnoreCase) намного медленнее в framework 4 (я тестировал с простым консольным приложением и в цикле время составляло 30 мс в 3.5 и 210 мс в 4.0 ???).Но сравнение в современной культуре происходит быстрее в рамках 4, чем 3.5.

Вот пример кода, который я использую:

int iMax = 100000;
String str  = "Mozilla/5.0+(Windows;+U;+Windows+NT+5.1;+fr;+rv:1.9.0.1)+Gecko/2008070208+Firefox/3.0.1";
Stopwatch sw = new Stopwatch();
sw.Start();
StringComparison s = StringComparison.OrdinalIgnoreCase;
for(int i = 1;i<iMax;i++)
{
    str.IndexOf("windows", s);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
Console.Read();

Мои вопросы:

  1. Кто-нибудь заметил такую ​​же проблему?

  2. У кого-то есть объяснение этого изменения?

  3. Есть ли решение, чтобы обойтипроблема?

спасибо.

Ответы [ 3 ]

5 голосов
/ 23 сентября 2010

Хорошо, у меня есть ответ на один из моих вопросов.

С отражателем я вижу разницу между рамками 2 и 4, и это объясняет мою проблему производительности.

    public int IndexOf(string value, int startIndex, int count, StringComparison comparisonType)
{
    if (value == null)
    {
        throw new ArgumentNullException("value");
    }
    if ((startIndex < 0) || (startIndex > this.Length))
    {
        throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
    }
    if ((count < 0) || (startIndex > (this.Length - count)))
    {
        throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
    }
    switch (comparisonType)
    {
        case StringComparison.CurrentCulture:
            return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.None);

        case StringComparison.CurrentCultureIgnoreCase:
            return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);

        case StringComparison.InvariantCulture:
            return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.None);

        case StringComparison.InvariantCultureIgnoreCase:
            return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);

        case StringComparison.Ordinal:
            return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.Ordinal);

        case StringComparison.OrdinalIgnoreCase:
            return TextInfo.IndexOfStringOrdinalIgnoreCase(this, value, startIndex, count);
    }
    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
}

Это базовый код функции IndexOf для 2-х фреймворков (без разницы между 4 и 2)

Но в функции TextInfo.IndexOfStringOrdinalIgnoreCase есть различия:

Framework 2:

    internal static unsafe int IndexOfStringOrdinalIgnoreCase(string source, string value, int startIndex, int count)
{
    if (source == null)
    {
        throw new ArgumentNullException("source");
    }
    return nativeIndexOfStringOrdinalIgnoreCase(InvariantNativeTextInfo, source, value, startIndex, count);
}

Framework 4:

    internal static int IndexOfStringOrdinalIgnoreCase(string source, string value, int startIndex, int count)
{
    if ((source.Length == 0) && (value.Length == 0))
    {
        return 0;
    }
    int num = startIndex + count;
    int num2 = num - value.Length;
    while (startIndex <= num2)
    {
        if (CompareOrdinalIgnoreCaseEx(source, startIndex, value, 0, value.Length, value.Length) == 0)
        {
            return startIndex;
        }
        startIndex++;
    }
    return -1;
}

Основной алгоритм изменился в framework 2, вызов - это nativeDll, который был удален из framework 4. Полезно знать

1 голос
/ 15 февраля 2013

Это известная проблема в .NET 4.

Вот отчет MS Connect .

0 голосов
/ 22 сентября 2010

Я не могу ответить на вашу конкретную проблему скорости .NET 4.

Однако вы, вероятно, получите гораздо большую скорость, если улучшите свой алгоритм .Проверьте алгоритм поиска строки Рабина-Карпа .

...