O que está acontecendo nos bastidores quando você marca uma expressão regular como uma a ser compilada? Como isso se compara / é diferente de uma expressão regular em cache?
Usando essas informações, como você determina quando o custo da computação é insignificante em comparação com o aumento de desempenho?
Respostas:
RegexOptions.Compiled
instrui o mecanismo de expressão regular a compilar a expressão regular em IL usando a geração de código leve ( LCG ). Essa compilação acontece durante a construção do objeto e o torna muito lento. Por sua vez, as correspondências usando a expressão regular são mais rápidas.Se você não especificar esse sinalizador, sua expressão regular será considerada "interpretada".
Veja este exemplo:
Ele realiza 4 testes em 3 expressões regulares diferentes. Primeiro, ele testa uma partida única (compilada vs não compilada). Segundo, ele testa correspondências repetidas que reutilizam a mesma expressão regular.
Os resultados na minha máquina (compilado na versão, sem depurador conectado)
1000 correspondências simples (construa Regex, corresponda e descarte)
1.000.000 correspondências - reutilizando o objeto Regex
Esses resultados mostram que expressões regulares compiladas podem ser até 60% mais rápidas nos casos em que você reutiliza o
Regex
objeto. No entanto, em alguns casos, pode ser mais de três ordens de magnitude mais lenta a ser construída.Também mostra que a versão x64 do .NET pode ser 5 a 6 vezes mais lenta quando se trata de compilação de expressões regulares.
A recomendação seria usar a versão compilada nos casos em que
Chave inglesa em obras, o cache Regex
O mecanismo de expressão regular contém um cache LRU que contém as últimas 15 expressões regulares testadas usando os métodos estáticos da
Regex
classe.Por exemplo:
Regex.Replace
,Regex.Match
etc .. todos usam o cache de Regex.O tamanho do cache pode ser aumentado pela configuração
Regex.CacheSize
. Ele aceita alterações de tamanho a qualquer momento durante o ciclo de vida do seu aplicativo.Novas expressões regulares são armazenadas em cache apenas pelos auxiliares estáticos na classe Regex. Se você construir seus objetos, o cache será verificado (para reutilização e colidido), no entanto, a expressão regular que você construir não será anexada ao cache .
Esse cache é um cache LRU trivial , é implementado usando uma lista simples de dupla ligação. Se você aumentar para 5000 e usar 5000 chamadas diferentes nos auxiliares estáticos, toda construção de expressão regular rastreará as 5000 entradas para ver se ela foi armazenada em cache anteriormente. Há uma trava ao redor da verificação, portanto, a verificação pode diminuir o paralelismo e introduzir o bloqueio de threads.
O número é muito baixo para se proteger de casos como esse, embora em alguns casos você possa não ter escolha a não ser aumentá-lo.
Minha forte recomendação seria nunca passar a
RegexOptions.Compiled
opção a um ajudante estático.Por exemplo:
O motivo é que você está arriscando muito a perda do cache LRU, o que desencadeará uma compilação muito cara . Além disso, você não tem idéia do que as bibliotecas das quais você depende estão fazendo, portanto, tem pouca capacidade de controlar ou prever o melhor tamanho possível do cache.
Veja também: blog da equipe BCL
Nota : isso é relevante para o .NET 2.0 e o .NET 4.0. Há algumas mudanças esperadas no 4.5 que podem fazer com que isso seja revisado.
fonte
Compiled
no código do site onde estou armazenando umRegex
objeto estático (em todo o aplicativo) . Portanto, oRegex
único precisa ser construído uma vez quando o IIS inicia o aplicativo e, em seguida, é reutilizado milhares de vezes. Isso funciona bem desde que o aplicativo não seja reiniciado com frequência.Esta entrada no Blog da equipe BCL fornece uma boa visão geral: " Desempenho da expressão regular ".
Em resumo, existem três tipos de regex (cada um executando mais rápido que o anterior):
interpretado
rápido para criar em tempo real, lento para executar
compilado (o que você parece perguntar)
mais lento para criar em tempo real, rápido para executar (bom para execução em loops)
pré-compilado
crie no momento da compilação do seu aplicativo (sem penalidade na criação em tempo de execução), rápido para executar
Portanto, se você pretende executar a regex apenas uma vez, ou em uma seção não crítica ao desempenho do seu aplicativo (por exemplo, validação de entrada do usuário), está bem com a opção 1.
Se você deseja executar o regex em um loop (ou seja, análise de arquivo linha por linha), você deve seguir a opção 2.
Se você tiver muitas regexes que nunca serão alteradas para seu aplicativo e forem usadas intensamente, você poderá optar pela opção 3.
fonte
CompileModule
. Porra, eu preciso dar uma olhada mais profunda na nova plataforma.Observe que o desempenho de expressões regulares desde o .NET 2.0 foi aprimorado com um cache MRU de expressões regulares não compiladas. O código da biblioteca Regex não reinterpreta sempre a mesma expressão regular não compilada.
Portanto, há potencialmente uma penalidade de desempenho maior com uma expressão regular compilada e dinâmica. Além de tempos de carregamento mais lentos, o sistema também usa mais memória para compilar a expressão regular para códigos de operação.
Essencialmente, o conselho atual é não compilar uma expressão regular ou compilá-las antecipadamente em um assembly separado.
Ref: BCL Team Blog Desempenho da expressão regular [David Gutierrez]
fonte
1) Equipe da Biblioteca de Classes Base no regex compilado
2) Codificação de Horror, referenciando o número 1 com alguns pontos positivos sobre as compensações
fonte
Espero que o código abaixo o ajude a entender o conceito de funções re.compile
fonte