.Net 5 Regex Performance

wmalves

Wellington Martins

Posted on October 11, 2021

.Net 5 Regex Performance

Olá pessoal!

Hoje vamos fazer um teste de performance utilizando regex com .net 5.

Para esse teste criaremos um console application com a instalção de 2 pacotes nuget:

dotnet new console name TestePerformanceRegex
dotnet add package BenchmarkDotNet
dotnet add package Bogus
Enter fullscreen mode Exit fullscreen mode

BenchmarkDotNet é o pacote responsável por realizar nosso benchmark.

Bogus é o pacote responsável por gerar os dados para nossos testes.

Nosso console app será composto por duas classes:

  1. Program.cs
  2. TesteRegex.cs

image

Nossa classe Program.cs será dessa forma:

class Program
{
    static void Main(string[] args)
    {
        BenchmarkRunner.Run<TesteRegex>();
    }
}
Enter fullscreen mode Exit fullscreen mode

Nossa classe TesteRegex.cs deverá ter o annotation [MemoryDiagnoser]

[MemoryDiagnoser]
public class TesteRegex
{
}
Enter fullscreen mode Exit fullscreen mode

Agora vamos criar uma classe Usuário, onde teremos E-mail e Login:

public class Usuario
{
    public string Email { get; set; }
    public string Login{ get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Agora dentro da classe TesteRegex, vamos fazer o seguinte:

private static readonly List<Usuario> FakeUsuarios = new Faker<Usuario>()
    .UseSeed(420)
    .RuleFor(r => r.Email, faker => faker.Person.Email)
    .RuleFor(r => r.Login, faker => faker.Person.UserName)
    .Generate(10);
Enter fullscreen mode Exit fullscreen mode

Estamos criando 10 usuários, utilizando o Bogus.

Agora vamos criar uma lista com e-mails validos e e-mails inválidos:

private static readonly List<string> emails = 
    FakeUsuarios.Select(x => x.Email)
        .Concat(FakeUsuarios.Select(x => x.Login)).ToList();
Enter fullscreen mode Exit fullscreen mode

Com isso teremos um total de 20 itens na lista e-mails.

Agora faremos os regex abaixo:

private static readonly Regex RegexStatico =
    new(@"^[^@\s]+@[^@\s]+\.[^@\s]+$", RegexOptions.IgnoreCase);

private static readonly Regex RegexStaticoCompilado =
    new(@"^[^@\s]+@[^@\s]+\.[^@\s]+$", RegexOptions.IgnoreCase | RegexOptions.Compiled,
        TimeSpan.FromMilliseconds(250));
Enter fullscreen mode Exit fullscreen mode

Com isso temos o primeiro Regex sendo estático e o segundo estático e compilado, também foi informado um timeout de 250 milissegundos. Esse timeout deve ser configurado conforme a necessidade da sua aplicação.

Agora iremos criar os métodos responsáveis pelos testes.

Importante ressaltar que todos os métodos tem a anotação de [Benchmark].

[Benchmark]
public void IsMatchInternal()
{
    var regex = new Regex(@"^[^@\s]+@[^@\s]+\.[^@\s]+$", RegexOptions.IgnoreCase);

    for (var i = 0; i < emails.Count; i++)
    {
        var email = emails[i];
        var isMatch = regex.IsMatch(email);
    }
}
Enter fullscreen mode Exit fullscreen mode

No método acima, estamos declarando o regex internamente e fazendo a validação de todos os e-mails da nossa lista.

[Benchmark]
public void IsMatchInternalCompiled()
{
    var regex = new Regex(@"^[^@\s]+@[^@\s]+\.[^@\s]+$", RegexOptions.IgnoreCase | 
                    RegexOptions.Compiled);

    for (var i = 0; i < emails.Count; i++)
    {
        var email = emails[i];
        var isMatch = regex.IsMatch(email);
    }
}
Enter fullscreen mode Exit fullscreen mode

Já no método acima, estamos declarando o regex internamente e a flag de compilado.

[Benchmark]
public void IsMatchStatic()
{
    for (var i = 0; i < emails.Count; i++)
    {
        var email = emails[i];
        var isMatch = RegexStatico.IsMatch(email);
    }
}
Enter fullscreen mode Exit fullscreen mode

Nesse método estamos utilizando a declaração estática RegexStatico ao invés de declararmos internamente no método.

[Benchmark]
public void IsMatchStaticCompiled()
{
    for (var i = 0; i < emails.Count; i++)
    {
        var email = emails[i];
        var isMatch = RegexStaticoCompilado.IsMatch(email);
    }
}
Enter fullscreen mode Exit fullscreen mode

Finalmente o último método, temos a utilização da declaração estática RegexStaticoCompilado com a flag de compilado.

Agora vamos executar nossa aplicação, é importante ressaltar que devemos executá-la em modo Release.
image
Após executarmos, teremos o resultado no console:
image
Podemos ver que o método mais performático de todos foi quando utilizamos a declaração estática com a flag de compilado, onde levou 4 microssegundos.

Já o nosso pior cenário foi quando utilizamos a declaração interna e copilada, onde levou 1.9 milissegundos e foi alocado 18KB de memória.

Com alguns ajustes simples podemos ter um ganho expressivo de performance quando estamos trabalhando com regex.

Abaixo link do código no github:
https://github.com/ouell/regex-performance

💖 💪 🙅 🚩
wmalves
Wellington Martins

Posted on October 11, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

.Net 5 Regex Performance
csharp .Net 5 Regex Performance

October 11, 2021