DEV Community

Cover image for .Net 5 Regex Performance
Wellington Martins
Wellington Martins

Posted on • Edited on

3 2

.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

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more →

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Engage with a sea of insights in this enlightening article, highly esteemed within the encouraging DEV Community. Programmers of every skill level are invited to participate and enrich our shared knowledge.

A simple "thank you" can uplift someone's spirits. Express your appreciation in the comments section!

On DEV, sharing knowledge smooths our journey and strengthens our community bonds. Found this useful? A brief thank you to the author can mean a lot.

Okay