Muitas dimensões são ruins para você

Rafael Steil

Veja possíveis problemas que você pode ter com arrays multi-dimensionais, e como resolver isso.



Muitas dimensões são ruins para você

Bem vindo à edição de número 70 da The Java(tm) Specialists' Newsletter, onde daremos uma breve olhada em arrays multi-dimensionais. Vários artigos estão disponíveis sobre este problema, então, nesta newsletter, irei direto ao ponto com um exemplo. Gostaria de agradecer a Roy Emmerich (Peralex in Cape Town), Pieter Potgieter e Louis Pool from Grintek Ewation por me lembrarem deste problema e por enviarem um programa de teste que ilustra isso.

Uma das coisas que aprendemos na escola primária do Java é que devemos evitar arrays multi-dimensionais assim como evitamos uma praga. Um array é um objeto por natureza, e quando você tem arrays de várias dimensões, você tem arrays de objetos. Navegar por eles consome um processamento considerável. Ao invés de construir um array multi-dimensional de tamanho n por m, construa um array de uma única dimensão de tamanho n vezes m e então calcule a posição você mesmo.

01 public class MultiDimensions {
02     private final static int NUM_BINS = 1000;
03     private final static int ITERATIONS = 10000;
04 
05     public static void main(String[] args) {
06         testMultiArray();
07         testMultiArray2();
08         testSingleArray();
09     }
10 
11     private static void testMultiArray() {
12         long time = -System.currentTimeMillis();
13         // Apenas certificando que o número de operações é igual
14         int ops = 0;
15 
16         for (int repeat = 0; repeat < ITERATIONS; repeat++) {
17             int[][] aTwoDim = new int[NUM_BINS][4];
18             for (int i = 0; i < aTwoDim.length; i++) {
19                 for (int j = 0; j < aTwoDim[i].length; j++) {
20                     ops++;
21                     aTwoDim[i][j= j;
22                 }
23             }
24         }
25 
26         time += System.currentTimeMillis();
27         System.out.println(ops);
28         System.out.println("Tempo necessário para [][4] - " + time);
29     }
30 
31     private static void testMultiArray2() {
32         long time = -System.currentTimeMillis();
33         int ops = 0;
34 
35         for (int repeat = 0; repeat < ITERATIONS; repeat++) {
36             int[][] aTwoDim = new int[4][NUM_BINS];
37             for (int i = 0; i < aTwoDim.length; i++) {
38                 for (int j = 0; j < aTwoDim[i].length; j++) {
39                     ops++;
40                     aTwoDim[i][j= j;
41                 }
42             }
43         }
44 
45         time += System.currentTimeMillis();
46         System.out.println(ops);
47         System.out.println("Tempo necessário para [4][] - " + time);
48     }
49 
50     private static void testSingleArray() {
51         long time = -System.currentTimeMillis();
52         int ops = 0;
53 
54         for (int repeat = 0; repeat < ITERATIONS; repeat++) {
55             int[] aOneDim = new int[NUM_BINS * 4];
56             for (int i = 0; i < aOneDim.length/4; i++) {
57                 for (int j = 0; j < 4; j++) {
58                     ops++;
59                     aOneDim[i*+ j= j;
60                 }
61             }
62         }
63 
64         time += System.currentTimeMillis();
65         System.out.println(ops);
66         System.out.println("Tempo necessário  para [] - " + time);
67     }
68 }


Em meus testes usando um cliente hotspot JDK 1.4.1, tive o seguinte resultado:

40000000
Tempo necessário para [][4] - 4226
40000000
Tempo necessário para [4][] - 631
40000000
Tempo necessário para [] - 671



Com um hotspot server, os resultados são ligeiramente melhores:

40000000
Tempo necessário para [][4] - 3675
40000000
Tempo necessário para [4][] - 350
40000000
Tempo necessário para [] - 561


Os resultados são esclarecedores. Se voce tem um array com um index primário grande, você se dará melhor usando um array de dimensão única. Sob o server hotspot, o array multi-dimensional com um index primário pequeno se sai um pouco melhor que o array de dimensão única.




Vendo mais cuidadosamente...
Um de nossos assinantes, Martin Schulte, da Alemanha, enviou uma correção para a última newsletter, e eu não gostaria de esperar muito tempo para publicar a correção, uma vez que é bem significante.

Martin descobriu que a maior diferença na performance é na criação de arrays multi-dimensionais. Mark Grand também pensou que eu deveria retificar que não há arrays multi-dimensionais no Java, somente arrays de arrays. Esta é a razão que temos uma diferença na performance quando criamos tais arrays de arrays

A diferença no tempo de criação pode ser vista no pequeno exemplo abaixo. Deixei sem o sintax highlighting para ver a sua reação ;-)


01 public class CreationTimes {
02     private final    static int ITERATIONS =    1000000;
03     private final    static int NUM_BINS    = 20;
04     private final    static int THE_OTHER_DIM = 4;
05 
06     public static    void main(String[] args) {
07         testMultiArray();
08         testMultiArray2();
09         testSingleArray();
10     }
11 
12     private static void testMultiArray() {
13         long time =    -System.currentTimeMillis();
14 
15         for    (int repeat    = 0; repeat    < ITERATIONS; repeat++)    {
16         int[][] aTwoDim =    new    int[NUM_BINS][THE_OTHER_DIM];
17         }
18 
19         time +=    System.currentTimeMillis();
20         System.out.println("Tempo necessário para [][" + THE_OTHER_DIM + "]    - "    
21                         time);
22     }
23 
24     private static void testMultiArray2()    {
25         long time =    -System.currentTimeMillis();
26 
27         for    (int repeat    = 0; repeat    < ITERATIONS; repeat++)    {
28         int[][] aTwoDim =    new    int[THE_OTHER_DIM][NUM_BINS];
29         }
30 
31         time +=    System.currentTimeMillis();
32         System.out.println("Tempo necessário para [" + THE_OTHER_DIM + "][]    - "    
33                         time);
34     }
35 
36     private static void testSingleArray()    {
37         long time =    -System.currentTimeMillis();
38 
39         for    (int repeat    = 0; repeat    < ITERATIONS; repeat++)    {
40         int[]    aOneDim    = new int[NUM_BINS * THE_OTHER_DIM];
41         }
42 
43         time +=    System.currentTimeMillis();
44         System.out.println("Tempo necessário para [] - " + time);
45     }
46 }


O resultado the rodar este código é o seguinte:


Tempo necessário para [][4] - 9653
Tempo necessário para [4][] - 2394
Tempo necessário para [] - 671



Atenciosamente,

Heinz

Sobre a The Java Specialists Newsletter

Este artigo é fruto de uma parceria entre o GUJ e o autor da The Java Specialists Newsletter, Dr. Heinz M. Kabutz. Originalmente publicadas em inglês e enviadas para milhares de leitores ao redor do planeta, o GUJ propô-se a realizar a tradução para o Português do conteúdo, disponibilizando assim um ótimo material para um número ainda maior de leitores.

Você encontra o documento original, assim como newsletters anteriores, no site oficial, em http://www.javaspecialists.co.za.



Copyright © 2002-2006 GUJ | Todas as marcas e marcas registradas que aparecem no GUJ são de propriedade de seus respectivos donos