Only Numbers performance test

wmalves

Wellington Martins

Posted on October 19, 2021

Only Numbers performance test

Olá pessoal, tudo blz?

Quem nunca se deparou com a necessidade de extrair somente os números de uma string?

Hoje iremos realizar alguns testes de performance utilizando algumas abordagens diferentes para realização dessa tarefa.

Primeiro vamos criar nossa aplicação, ela será um console application em .net 5

dotnet new console --name OnlyNumbers
Enter fullscreen mode Exit fullscreen mode

Feito isso já temos nossa aplicação criada. Agora vamos instalar dois pacotes nugets que irão nos ajudar.

dotnet add package Bogus
dotnet add package BenchmarkDotNet
Enter fullscreen mode Exit fullscreen mode

O primeiro pacote será responsável pela criação da nossa massa de dados.

O segundo é responsável por realizar nosso teste de performance e suas métricas.

Feito isso, abra a aplicação em sua IDE de preferência, eu utilizei o Rider da JetBrains.

Com isso, teremos nossa classe Program.cs.

Iremos adicionar mais uma classe com o nome de OnlyNumberTests.cs

Dentro desse arquivo iremos criar uma segunda classe que será a User

public class User
{
    public string Login { get; set; }
    public string Password { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Uma classe bem simples contendo somente Login e Password.

De volta a classe OnlyNumberTests, iremos adicionar o annotation [MemoryDiagnoser].

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

Vamos criar nossa lista de usuários utilizando a biblioteca Bogus da seguinte forma:

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

Vamos criar também o Regex abaixo:

private static readonly Regex OnlyNumberPattern =
            new(@"\d+", RegexOptions.IgnoreCase
                        | RegexOptions.Compiled,
                TimeSpan.FromMilliseconds(250));
Enter fullscreen mode Exit fullscreen mode

Agora faremos nosso primeiro método de teste, conforme abaixo:

[Benchmark]
public void LinqCharIsDigitNewString()
{
    for (var i = 0; i < FakeUsers.Count; i++)
    {
        var numbers = new string(FakeUsers[i].Password.Where(char.IsDigit).ToArray());
    }
}
Enter fullscreen mode Exit fullscreen mode

Estamos percorrendo nossa lista de usuários e pesquisando somente pelos caracteres que são dígitos utilizando uma função do próprio .net chamada char.IsDigit().

Feito isso, estamos retornando uma nova string somente com os dígitos.

O segundo método é bem semelhante ao primeiro, somente alteramos a forma como é salva a string ao invés de criar uma nova string utilizando o string.Join():

[Benchmark]
public void LinqCharIsDigitStringJoin()
{
    for (var i = 0; i < FakeUsers.Count; i++)
    {
        var numbers = string.Join("", FakeUsers[i].Password.Where(char.IsDigit).ToArray());
    }
}
Enter fullscreen mode Exit fullscreen mode

Agora vamos para o método que utilizará o Regex:

[Benchmark]
public void RegexMatchOnlyNumberPattern()
{
    for (var i = 0; i < FakeUsers.Count; i++)
    {
        var number = OnlyNumberPattern.Match(FakeUsers[i].Password).Value;
    }
}
Enter fullscreen mode Exit fullscreen mode

Nosso último método efetuará validação na "mão":

[Benchmark]
public void IfValidator()
{
    for (var i = 0; i < FakeUsers.Count; i++)
    {
        var digitsOnly = string.Empty;
        foreach (var c in FakeUsers[i].Password)
        {
            if (c is >= '0' and <= '9') 
                digitsOnly += c;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Ele verificará caractere por caractere, caso seja um número ele adiciona a nossa string.

Agora vamos executar nossa aplicação, importante ressaltar que devemos executá-la em modo Release.

Image description

Após executá-la teremos o resultado abaixo no console:

Method Mean Allocated
LinqCharIsDigitNewString 1,918.3 ns 2,432 B
LinqCharIsDigitStringJoin 2,327.8 ns 3,016 B
RegexMatchOnlyNumberPattern 1,497.0 ns 2,352 B
IfValidator 267.8 ns 632 B

Onde é possível verificar que a validação com IF foi mais performática que os outros cenários. Levando 267 nanossegundos tendo uma alocação de 632 Bytes.

Já nosso pior cenário foi com a utilização do linq com string join. Levando 2,3 microssegundos alocando 3KB de memória.

Abaixo link do código no github:
https://github.com/ouell/only-numbers

💖 💪 🙅 🚩
wmalves
Wellington Martins

Posted on October 19, 2021

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

Sign up to receive the latest update from our blog.

Related

Only Numbers performance test
csharp Only Numbers performance test

October 19, 2021