Dev (Back & Front)ARTIGO

Melhorando o desempenho de aplicativos .NET – Parte 13

No último artigo, nós discutimos como otimizar as operações string no .NET. Hoje vamos focar na otimização de arrays.

Os arrays oferecem funcionalidades básicas para os tipos de agrupamento. Toda linguagem implementa sintaxe de array à sua maneira, embora as seguintes considerações se apliquem independentemente da linguagem:

  • Os arrays têm um tamanho estático. Ele permanece fixo após a alocação inicial. Se precisar estender o tamanho do array, você deve criar um novo array com o tamanho necessário e, em seguida, copiar os elementos do array antigo;
  • Arrays dão suporte ao acesso indexado. Para acessar um item em um array, você pode usar seu índice;
  • Arrays oferecem suporte o acesso enumerador. Você pode acessar os itens no array por enumeração, através dos conteúdos usando a construção foreach (C #) ou For Each (Visual Basic NET);
  • A memória é contígua. O CLR organiza arrays em espaços de memória próximos, que fornecem acesso rápido aos itens.

Esta seção resume as diretrizes de desempenho para se considerar ao usar arrays:

  • Prefira arrays para coleções – a menos que você precise de funcionalidade;
  • Use arrays fortemente tipadas;
  • Use arrays de arrays ao invés de arrays multidimensionais.

Prefira arrays para as coleções – a menos que precise de funcionalidade

Arrays são os mais rápidos de todas as coleções, a menos que você precise de uma funcionalidade em especial, como extensão dinâmica da coleção, você deve considerar o uso de arrays ao invés de coleções. Arrays também evitam a sobrecarga de boxing e unboxing.

Use arrays fortemente tipadas

Use arrays fortemente tipadas sempre que possível, ao invés de usar arrays de objeto para armazenar os tipos. Isto evita a conversão de tipo ou o boxing, dependendo do tipo armazenado no array. Se declarar um array de objetos e, em seguida, proceder para adicionar um tipo de valor, como um inteiro ou um float, para o array, isso envolve a sobrecarga de boxing, como mostrado no seguinte exemplo de código:

Object[] array = new Object[10]

arr[0] = 2+3; //boxing occurs here

Para evitar a sobrecarga do boxing, declare um arry fortemente tipado, como mostrado a seguir:

int [] arrIn = new int [10];

arrIn[0] = 2+3;

Tipos de referência de armazenamento, tais como strings ou classes personalizadas no array de objetos, envolve a sobrecarga do método. Portanto, use matrizes fortemente tipadas para armazenar os seus tipos de referência, como mostrado no seguinte exemplo de código:

string[10]  arrStr = new string[10];

arrStr[0] =  new string(“abc”);

Use arrays de arrays ao invés de arrays multidimensionais

Os elementos de um array de arrays podem ter dimensões e tamanhos diferentes. Use arrays de arrays ao invés de arrays multidimensionais para se beneficiar a partir das otimizações de desempenho MSIL.

O MSIL possui instruções específicas que visam arrays com uma única dimensão baseado em zero (SZArrays) e o acesso a este tipo de array é otimizado. Em contraste, os arrays multidimensionais são acessadas usando o mesmo código genérico para todos os tipos, o que resulta em boxing e unboxing para arrays de tipos primitivos.

Vejamos um exemplo mostrando a declaração e o uso de arrays de arrays:

string[][] Address = new string[2][];  // A jagged array of strings

Address[0] = new string[1];

Address[1] = new string[2];

Address[0][0] = “Address [0,1]“;

Address[1][0] = “Address [1,0]“;

Address[1][1] = “Address [1,1]“;

for (int i =0; i <=1; i++) {

      for (int j = 0; j < Address[i].Length; j ++)

            MessageBox.Show(Address[i][j]);

}

Você pode comparar a eficiência de arrays de arrays vs multidimensionais estudando o código MSIL gerado em cada caso. Observe como o código a seguir, que usa um array multidimensional, resulta em uma chamada de função:

int [,] secondarr = new int[1, 2];

secondarr[0, 0] = 40;

O código anterior gera o MSIL seguinte. Observe a chamada de função:

IL_0029: ldc.i4.s   40

IL_002b: call instance void int32[0...,0...]::Set(int32,int32,int32)

O código a seguir mostra o MSIL gerado por um array de arrays. Observe a instrução MSIL Stelem que substitui o elemento do array em um determinado índice com o valor int32 na pilha de avaliação:

int [][] intarr = new int[1][];

intarr[0] = new int[2];

intarr[0][0] = 10;

O código anterior gera o MSIL seguinte. Observe a utilização da instrução Stelem:

IL_001c:  ldc.i4.s   10

IL_001e:  stelem.i4

Considerações adicionais

Ao usar matrizes você também deve considerar o seguinte:

  • Ordenação. Se você recuperar os dados de um banco de dados, veja se é possível classificá-los previamente usando uma cláusula ORDER BY na sua consulta. Se precisa usar os resultados classificados do banco de dados para pesquisa adicional e classificação do subconjunto de resultados, você pode exigir a classificação dos arrays. Você sempre deve medir para descobrir qual abordagem vai funcionar melhor para o seu cenário: ordenação, utilizando consultas SQL, ou ordenação utilizando arrays na camada de negócios.
  • Evite retornar um array de uma propriedade. Em vez disso, considere o uso de propriedades de indexação.
EmployeeList l = FillList();

for (int i = 0; i < l.Length; i++) {

   if (l.All[i] == x){…}

}

No código anterior, cada vez que a propriedade All é usada, você pode criar e retornar um array. Se o código de chamada usa a propriedade em um loop, como mostrado no anterior, será criada um array em cada iteração do loop.

Além disso, se você retornar um array de um método, o código resultante é um pouco não intuitivo. Um exemplo de código está a seguir. Em ambos os casos, documente os detalhes para sua API.

// calling code:

if (l.GetAll()[i]== x) {…}

Se você tiver que retornar um array de uma parte de código, considere o envio de uma cópia para evitar problemas de sincronização entre os clientes.

  • No seguinte exemplo de código, cada chamada para a propriedade myObj cria uma cópia do array. Como resultado, uma cópia do array será criada a cada vez que o código DoSomething (obj.myObj [i]) for executado.
for (int i = 0; i < obj.myObj.Count; i++)

      DoSomething(obj.myObj[i]);

Em nosso próximo artigo veremos como otimizar o trabalhar com coleções.

***

O artigo original está disponível em: http://blog.monitis.com/index.php/2012/05/15/improving-net-application-performance-part-13-arrays/

é CEO do Monitis, um provedor de gerenciamento de sistemas e de monitoramento de software on-demand.

Ver perfil