Tengo una regex de C# grande y compleja que funciona bien cuando se interpreta, pero es un poco lenta. Estoy tratando de acelerar esto configurando RegexOptions.Compiled
, y esto parece tomar unos 30 segundos por primera vez e inmediatamente después de eso. Intento negar esto compilando la expresión regular a un ensamblado primero, por lo que mi aplicación puede ser lo más rápida posible.¿Por qué mi expresión regular es mucho más lenta que la compilada?
Mi problema es cuando el retraso compilación se lleva a cabo, ya sea compilada en la aplicación:
Regex myComplexRegex = new Regex(regexText, RegexOptions.Compiled);
MatchCollection matches = myComplexRegex.Matches(searchText);
foreach (Match match in matches) // <--- when the one-time long delay kicks in
{
}
o el uso de Regex.CompileToAssembly con antelación:
MatchCollection matches = new CompiledAssembly.ComplexRegex().Matches(searchText);
foreach (Match match in matches) // <--- when the one-time long delay kicks in
{
}
Esto está haciendo compilando a un ensamblaje básicamente inútil, ya que todavía tengo el retraso en la primera llamada foreach
. Lo que quiero es que todo el retraso de compilación se realice en tiempo de compilación (en la llamada Regex.CompileToAssembly) y no en tiempo de ejecución. ¿Dónde estoy equivocado?
(El código que estoy utilizando para compilar un ensamblado es similar al http://www.dijksterhuis.org/regular-expressions-advanced/, si es relevante).
Editar:
debo utilizar new
al llamar al ensamblado compilado en new CompiledAssembly.ComplexRegex().Matches(searchText);
? Sin embargo, da un error de "referencia de objeto requerido" sin él.
Actualización 2
Gracias por las respuestas/comentarios. La expresión regular que estoy usando es bastante larga, pero básicamente sencilla, una lista de miles de palabras, cada una separada por |. No puedo ver que sería un problema de retroceso realmente. La cadena de asunto puede tener una sola letra de longitud, y aún puede causar el retraso de compilación. Para una expresión regular RegexOptions.Compiled, tardará más de 10 segundos en ejecutarse cuando la expresión regular contenga 5000 palabras. A modo de comparación, la versión no compilada de la expresión regular puede tomar más de 30,000 palabras y aun así ejecutarse casi al instante.
Después de hacer muchas pruebas sobre este tema, lo que creo que he descubierto es:
- no utilice RegexOptions.Compiled cuando su expresión regular tiene muchas alternativas - que puede ser muy lento para que compilar.
- .Net usará lazy evaluation for regex cuando sea posible, y AFAI puede ver que esto se extiende (al menos hasta cierto punto) también a la compilación de expresiones regulares. Una expresión regular se compilará por completo solo cuando deba serlo, y parece que no hay forma de forzar la compilación antes de tiempo.
- Regex.CompileToAssembly sería mucho más útil si se pudiera obligar a las expresiones regulares a compilarse por completo, parece que ya casi no tiene sentido.
¡Corríjame si me equivoco o extraño algo!
Quizás deba intentar compartir la expresión real involucrada y una entrada de muestra, que le da este comportamiento. – driis
Gracias por esta publicación. Tuve el mismo problema con algunos Regex de Twitter portado desde Java a .NET. Tanto RegexOptions.Compiled como .CompileToAssembly causaron que la aplicación se cuelgue durante ~ 10 segundos la primera vez que intenta coincidir. Se ha eliminado Regex.Compiled y todo es instantáneo. – LongZheng
MSDN agregó un artículo de mejores prácticas para .NET 4 que se refería a [compilaciones de regex compiladas] (http://msdn.microsoft.com/en-us/library/gg578045.aspx#sectionToggle4). –