¿Qué sucede detrás de escena cuando marca una expresión regular como una para compilar? ¿Cómo se compara / es diferente de una expresión regular en caché?
Con esta información, ¿cómo determina cuándo el costo de la computación es insignificante en comparación con el aumento del rendimiento?
Respuestas:
RegexOptions.Compiled
indica al motor de expresión regular que compile la expresión de expresión regular en IL utilizando la generación de código ligero ( LCG ). Esta compilación ocurre durante la construcción del objeto y lo ralentiza mucho . A su vez, las coincidencias que utilizan la expresión regular son más rápidas.Si no especifica este indicador, su expresión regular se considera "interpretada".
Toma este ejemplo:
Realiza 4 pruebas en 3 expresiones regulares diferentes. Primero, prueba una sola vez una partida (compilada vs no compilada). En segundo lugar, prueba las coincidencias repetidas que reutilizan la misma expresión regular.
Los resultados en mi máquina (compilados en la versión, sin depurador adjunto)
1000 partidos individuales (construir Regex, Match y disponer)
1,000,000 coincidencias - reutilizando el objeto Regex
Estos resultados muestran que las expresiones regulares compiladas pueden ser hasta un 60% más rápidas para los casos en los que reutiliza el
Regex
objeto. Sin embargo, en algunos casos puede ser más de 3 órdenes de magnitud más lento de construir.También muestra que la versión x64 de .NET puede ser de 5 a 6 veces más lenta cuando se trata de compilar expresiones regulares.
La recomendación sería utilizar la versión compilada en los casos en que
Llave en proceso, el caché Regex
El motor de expresiones regulares contiene un caché LRU que contiene las últimas 15 expresiones regulares que se probaron utilizando los métodos estáticos en la
Regex
clase.Por ejemplo:
Regex.Replace
,Regex.Match
etc .. todo el uso de la caché de expresiones regulares.El tamaño de la memoria caché se puede aumentar mediante la configuración
Regex.CacheSize
. Acepta cambios de tamaño en cualquier momento durante el ciclo de vida de su aplicación.Las nuevas expresiones regulares solo son almacenadas en caché por los ayudantes estáticos en la clase Regex. Sin embargo, si construye sus objetos, la memoria caché se verifica (para su reutilización y eliminación), la expresión regular que construye no se agrega a la memoria caché .
Este caché es un caché LRU trivial , se implementa utilizando una lista simple de doble enlace. Si lo aumenta a 5000 y usa 5000 llamadas diferentes en los ayudantes estáticos, cada construcción de expresión regular rastreará las 5000 entradas para ver si se ha almacenado previamente en caché. Hay un bloqueo alrededor del cheque, por lo que el cheque puede disminuir el paralelismo e introducir el bloqueo de hilos.
El número se establece bastante bajo para protegerse de casos como este, aunque en algunos casos puede que no tenga más remedio que aumentarlo.
Mi recomendación fuerte sería nunca pasarle la
RegexOptions.Compiled
opción a un ayudante estático.Por ejemplo:
La razón es que está arriesgando mucho una falla en la caché de LRU que desencadenará una compilación súper costosa . Además, no tiene idea de lo que están haciendo las bibliotecas de las que depende, por lo que tiene poca capacidad para controlar o predecir el mejor tamaño posible de la memoria caché.
Ver también: blog del equipo BCL
Nota : esto es relevante para .NET 2.0 y .NET 4.0. Hay algunos cambios esperados en 4.5 que pueden hacer que esto se revise.
fuente
Compiled
en el código del sitio web donde realmente estoy almacenando un objeto estático (para toda la aplicación)Regex
. Por lo tanto,Regex
solo se debe construir una vez cuando IIS inicia la aplicación, y luego se reutiliza miles de veces. Esto funciona bien siempre que la aplicación no se reinicie con frecuencia.Esta entrada en el Blog del equipo de BCL ofrece una buena descripción general: " Rendimiento de expresión regular ".
En resumen, hay tres tipos de expresiones regulares (cada una ejecutándose más rápido que la anterior):
interpretado
rápido para crear sobre la marcha, lento para ejecutar
compilado (el que parece preguntar)
más lento para crear sobre la marcha, rápido de ejecutar (bueno para la ejecución en bucles)
precompilado
cree en tiempo de compilación de su aplicación (sin penalización por creación en tiempo de ejecución), rápido de ejecutar
Por lo tanto, si tiene la intención de ejecutar la expresión regular solo una vez, o en una sección no crítica del rendimiento de su aplicación (es decir, validación de entrada del usuario), está bien con la opción 1.
Si tiene la intención de ejecutar la expresión regular en un bucle (es decir, análisis de archivo línea por línea), debe ir con la opción 2.
Si tiene muchas expresiones regulares que nunca cambiarán para su aplicación y se usan intensamente, puede optar por la opción 3.
fuente
CompileModule
. Maldición, necesito echar un vistazo más profundo a la nueva plataforma.Cabe señalar que el rendimiento de las expresiones regulares desde .NET 2.0 se ha mejorado con un caché MRU de expresiones regulares sin compilar. El código de la biblioteca Regex ya no reinterpreta la misma expresión regular sin compilar cada vez.
Por lo tanto, existe potencialmente una mayor penalización de rendimiento con una expresión regular compilada y sobre la marcha. Además de tiempos de carga más lentos, el sistema también usa más memoria para compilar la expresión regular en códigos de operación.
Esencialmente, el consejo actual es no compilar una expresión regular o compilarlas por adelantado en un ensamblaje separado.
Ref: BCL Team Blog Rendimiento de expresión regular [David Gutiérrez]
fuente
1) Equipo de biblioteca de clase base en expresiones regulares compiladas
2) Coding Horror, haciendo referencia al n. ° 1 con algunos buenos puntos en las compensaciones
fuente
Espero que el siguiente código lo ayude a comprender el concepto de recompilar funciones
fuente