Dicas para melhorar a performance em C# - parte 1
Tags: csharp, performance, programming
Published: 2022-06-07 18:11:25

Neste post, vamos comentar sobre algumas melhorias que podemos fazer para obter uma melhor performance do código produzido.

Algumas dicas podem se tornar irrelevantes se a quantidade de dados processada for pequena. Então, não precisa sair alterando seus códigos somente para obter uma melhora que é impercepível para o usuário.

Muitos desenvolvedores tem a preocupação de otimizar seus códigos, obtendo uma melhor performance em tempo de execução. Isso melhora a experiência de usuário, pois ele não ficará esperando tempo desnecessário aguardando uma resposta da aplicação. Além disso, economiza recursos de sistema.

Alguns exemplos foram encontrados em revisões de código que fiz e sugeri ou eu mesmo apliquei as melhorias.

## Como medir?
Para a medição da performance de código utilizaremos uma classe chamada [StopWatch](https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.stopwatch?view=net-6.0), pois é muito mais precisa do que a classe [DateTime](https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=net-6.0).

```
using System.Diagnostics;

var stopWatch = new Stopwatch();
stopWatch.Start();

//Código para teste

stopWatch.Stop();

Console.WriteLine("Tempo utilizado: {0}ms", stopWatch.ElapsedMilliseconds);
```
### Ordem de condições no IF

Muitas vezes, não prestamos atenção na ordem de condições no IF. No exemplo abaixo (não é dos melhores, eu sei), temos duas condições AcessaBanco() e isActive.

Não sabemos quanto tempo AcessaBanco() vai demorar para ser executado e qual será sua resposta: true ou false, mas temos isActive já fornecido.


```
public static void Exemplo1(int id, bool isActive)
{
    if (AcessaBanco(id) || isActive)
    {
        Console.WriteLine("entrou");
    }
}

```

Como temos uma condição OU [||](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators#conditional-logical-or-operator-), o código será executado quando uma das condições for verdadeira. Se o lado esquerdo for verdadeiro, logo, o lado não é executado.

Podemos mudar, então, para:

```
public static void Exemplo1(int id, bool isActive)
{
    if (isActive || AcessaBanco(id))
    {
        Console.WriteLine("entrou");
    }
    
}

```

### Operadores && e || vs & e |

Os operadores [&](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators#logical-and-operator-) e [|](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators#logical-or-operator-) avaliarão os dois lados do operando independente do resultado de cada um. 

Para começarmos, vamos definir os métodos:
```
public static bool ValidacaoA()
{
    Console.WriteLine("Validacao A");
    return true;
}

public static bool ValidacaoB()
{
    Console.WriteLine("Validacao B");
    return true;
}
```
Agora vamos ao teste.
No exemplo abaixo, os dois métodos abaixo serão executados.
```
if(ValidacaoA() | ValidacaoB())
{
    Console.WriteLine("Testou os dois");
}

//Saída
//Validacao A
//Validacao B
//Testou os dois
```

Já os operadores [&&](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators#conditional-logical-and-operator-) e [||](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators#conditional-logical-or-operator-)

```
bool a = false & PerformanceTeste.ValidacaoB();
Console.WriteLine(a);

//Saída
//Validacao B
//False

bool b = true & PerformanceTeste.ValidacaoB();
Console.WriteLine(b);

//Saída
//Validacao B
//True
```

Logo, se for possível, utilize os operandos && e ||.

### Comparar Strings

Para este teste, foi criada uma lista de 500.000 objetos. Cada objeto da lista contém duas propriedades do tipo string (chamei de MyProperty1 e MyProperty2). Foram geradas para cada propriedade uma string [aleatória](https://docs.microsoft.com/en-us/dotnet/api/system.random?view=net-6.0) de 50 posições.

No primeiro teste, foi utilizada a comparação **PALAVRA1** == **PALAVRA2**.

Ao executar o teste conforme o código abaixo, obteve-se o resultado de **80ms**.
```
public static bool Exemplo3(string str1, string str2)
{
    return str1.ToLower() == str2.ToLower();
}
```

Ao utilizar [string.Compare](https://docs.microsoft.com/en-us/dotnet/api/system.string.compare?view=net-6.0), obteve o resultado de **15ms**
```
public static bool Exemplo3Alterado(string str1, string str2)
{
    return string.Compare(str1,str2,true) == 0;
}
```

Ou seja, apenas com essa mudança obteve-se um melhora de 90%. Nada mal.

### List e ArrayList
O exemplo a seguir trata das diferenças de performance entre List e ArrayList.

Vamos deixar bem simples e utilizar apenas List e ArrayList com inteiros.

```
const int _tamanho = 100000;
public static void Exemplo4()
{
    ArrayList arrayList = new ArrayList();
    for (int i = 0; i < _tamanho; i++)
    {
        arrayList.Add(i);
    }

}
```
Obteve-se um resultado de 31ms.

Ao utilizarmos o List com um tamanho predefinido (uma forma de obter maior performance) teremos o seguinte: 0ms (!!)

```
const int _tamanho = 100000;
public static void Exemplo4Alterado()
{
    List<int> intlist = new List<int>(_tamanho);
    for (int i = 0; i < _tamanho; i++)
    {
        intlist.Add(i);
    }

}
```
 
Por enquanto é isso, em breve teremos a parte 2.
Abraços.