1
resposta

Fato curioso no tempo de execução da Hashset

Explorando um pouco mais a atividade Velocidade de busca das listas e conjuntos notei outra diferença entre os ArrayLists e HashSets.

Incluí as operações de inserção e verificação de elementos (Collection.add e Collection.contains) de ArrayList e HashSet dentro de funções próprias nominadas testePerformanceHashSet e testePerformanceArrayList, e as invoquei dentro de outra chamada executarTestes, até ai tudo certo, a proposta da atividade foi cumprida .. Mas por curiosidade decidi invocar este ultimo método dentro de um laço de 32 repetições e notei alguns pontos:

1. ArrayList manteve uma variação no tempo de execução entre 1727 e 1618 milissegundos durante toda a execução do laço for.

2. o HashSet por sua vez apresentou decréscimos desde o primeiro laço até estabilizar numa média entre 3 e 5 milissegundos e então no 16º laço apresentou um pico de 37 milissegundos.

3. Apartir do 16º laço o HashSet apresentou intervalos menores de 2, 4 laços com 5 a 6 milissegundos entre novos picos de tempo. Ou seja a numa média de cada dois ou quatro tempos menores um pico entre 38 e 20 milissegundos era registrado.

Finalizando ...

Achei muito curioso esse comportamento, de decréscimo até certo ponto e depois picos desproporcionais aos registros anteriores .. tenho ciência de que pode haver alguma ligação com processos da CPU no sentido de alocar os núcleos para execução da tarefa, mas o comportamento em si achei muito interessante. Caso alguém saiba explicar o porque disso, estarei esperando ansiosamente para saber hehehe.

Estou deixando o meu código e os registros dos tempos de execuções abaixo caso alguém queira fazer como eu fiz:

OBS: No meu Windows aumentei o desempenho do meu computador para alcançar os melhores tempos possíveis, tal coisa pode ser feita em "Escolher Plano de Energia" > selecione "Alto Desempenho".

--------------------------- RESULTADOS DE 32 TESTES CONSECULTIVOS -------------------------

ArrayList: 1712 HashSet: 28

ArrayList: 1618 HashSet: 10

ArrayList: 1685 HashSet: 8

ArrayList: 1727 HashSet: 6

ArrayList: 1696 HashSet: 3

ArrayList: 1669 HashSet: 4

ArrayList: 1649 HashSet: 4

ArrayList: 1683 HashSet: 4

ArrayList: 1703 HashSet: 4

ArrayList: 1642 HashSet: 3

ArrayList: 1639 HashSet: 4

ArrayList: 1642 HashSet: 4

ArrayList: 1652 HashSet: 4

ArrayList: 1654 HashSet: 5

ArrayList: 1642 HashSet: 5

ArrayList: 1666 HashSet: 35

ArrayList: 1669 HashSet: 4

ArrayList: 1645 HashSet: 4

ArrayList: 1627 HashSet: 4

ArrayList: 1638 HashSet: 4

ArrayList: 1637 HashSet: 39

ArrayList: 1618 HashSet: 5

ArrayList: 1628 HashSet: 5

ArrayList: 1665 HashSet: 20

ArrayList: 1641 HashSet: 9

ArrayList: 1671 HashSet: 4

ArrayList: 1649 HashSet: 4

ArrayList: 1645 HashSet: 4

ArrayList: 1655 HashSet: 32

ArrayList: 1625 HashSet: 4

ArrayList: 1657 HashSet: 3

ArrayList: 1633 HashSet: 4

Process finished with exit code 0

public class TestePerformance {

    public Collection numeros;
    public long inicio;
    public long fim;

    public static void main(String[] args) {
        TestePerformance testePerformance = new TestePerformance();
        System.out.println();
        System.out.println();
        System.out.println("--------------------------- RESULTADOS DE 32 TESTES CONSECULTIVOS -------------------------");
        testePerformance.executarTestesRepetidamente(32);
    }

    public void executarTestes() {
        long testeHashSet = testePerformanceHashSet();
        long testeArrayList = testePerformanceArrayList();
        System.out.println("ArrayList: " + testeArrayList);
        System.out.println("HashSet: " + testeHashSet);
        System.out.println();
    }

    public void executarTestesRepetidamente(int numeroDeVezes) {
        for (int i = 0; i < numeroDeVezes ; i++) {
            executarTestes();
        }
    }

    public long testePerformanceHashSet() {
        numeros = new HashSet<Integer>();

        inicio = System.currentTimeMillis();

        for (int i = 0; i <= 50000; i++) {
            numeros.add(i);
        }

        numeros.forEach(numero -> numeros.contains(numero));

        fim = System.currentTimeMillis();

        return fim - inicio;
    }

    public long testePerformanceArrayList() {
        numeros = new ArrayList<Integer>();

        inicio = System.currentTimeMillis();

        for (int i = 0; i <= 50000; i++) {
            numeros.add(i);
        }

        numeros.forEach(numero -> numeros.contains(numero));

        fim = System.currentTimeMillis();

        return fim - inicio;
    }
}
1 resposta

Olá!

Interessante a sua observação sobre o comportamento do HashSet em relação ao ArrayList. Realmente, é curioso ver que o tempo de execução do HashSet apresenta uma queda até certo ponto e, em seguida, picos desproporcionais aos registros anteriores.

Sobre o motivo desse comportamento, é possível que haja uma relação com o processo de alocação de núcleos da CPU para a execução da tarefa, como você mencionou. Além disso, pode haver outros fatores em jogo, como a forma como o HashSet lida com colisões e o tamanho da tabela de hash.

No entanto, é importante lembrar que o comportamento que você observou pode não ser reproduzido em outras máquinas ou em outras circunstâncias. Cada sistema possui suas particularidades e pode apresentar resultados diferentes.

De qualquer forma, é muito interessante ver que você está explorando e testando diferentes aspectos da linguagem Java e suas coleções. Isso certamente contribui para um melhor entendimento da linguagem e para o desenvolvimento de habilidades de programação.

Espero ter ajudado e bons estudos!