2010-09-22 7 views
6

Explicaré mi problema (disculpe mi mal inglés), tengo un exe .NET en el que cada milisegundos de procesamiento es muy importante.Comparación de cadenas en dotnet framework 4

Este programa hace muchas comparaciones de cadenas (la mayor parte es string1.IndexOf(string2, StringComparison.OrdinalIgnoreCase)).

Cuando cambio al marco 4, el tiempo de mi programa es el doble que antes.

He buscado una explicación y encontré que la función IndexOf(s, OrdinalIgnoreCase) es mucho más lenta en el marco 4 (hice la prueba con una simple aplicación de consola y en un bucle el tiempo fue de 30ms en 3.5 y 210ms en 4.0). Pero la comparación en la cultura actual es más rápida en el marco 4 que 3.5.

Aquí está un ejemplo de código que utilizo:

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(); 

Mis preguntas son:

  1. Alguien ha notado el mismo problema?

  2. ¿Alguien tiene una explicación sobre este cambio?

  3. ¿Existe una solución para eludir el problema?

Thanks.

+0

¿Están sus parámetros de cadena basados ​​en tipos de caracteres o tipos de cadenas? – ChrisBD

+0

parámetros de cadena – baz

Respuesta

5

Ok, tengo una respuesta a una de mis preguntas.

Con el reflector puedo ver la diferencia entre el marco 2 y 4 y eso explica mi problema de perforaciones.

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"); 
} 

Este es el código base de la función IndexOf del marco 2 (sin diferencia entre 4 y 2)

Pero en la función TextInfo.IndexOfStringOrdinalIgnoreCase hay diferencias:

Marco 2:

Marco
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); 
} 

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; 
} 

El algoritmo principal ha cambiado en marco 2 la llamada es una nativeDll que ha sido retirado del marco 4. Su bueno saber

0

No puedo responder a su problema específico de .NET 4 velocidad.

Sin embargo, probablemente ganaría mucha más velocidad al mejorando su algo. Consulte el Rabin-Karp string search algo.

+0

Sí, puedo usar otro algo pero quiero saber por qué el framework 4 es más lento que el framework 2. Reviso el Rabin-Karp gracias – baz

+0

No puedo decir que desde algunos puntos se dice que es más rápido. Puede ser más lento en otros. – Wernight