Pensando em Performance

8 respostas
saoj

Descobri hoje isso. Será frescura minha? Programar pensando sempre em performance deve ser um saco, mas tem gente que é mestre nisso…

Alguém sabe como deixar o código abaixo bem mais rápido?

private static final byte[] values = { 'a', 'x', 'd', 'y' };

public static boolean hasValue(byte value) {

    for(int i=0; i<values.length; i++) {

        if (value == values[i]) return true;

   }

   return false;
}

8 Respostas

F

Ordene o vetor e faça busca binária dos elementos.

Do jeito que está, cada consulta é O(n). Para ordenar vc gasta tempo O(nlogn), mas depois disso cada consulta cai para O(logn).

saoj

Busca binária será sempre melhor do que busca sequencial.

Mas tem um jeito ainda melhor do que esse que vc falou aí… E 10 vezes mais simples.

T

Se acesso a memória não fosse tão lento, eu inverteria a sua tabela, já que você só quer checar um byte. Algo como:

// private static final byte[] values = { 'a', 'x', 'd', 'y' };

private static final boolean[] invValues = { /*0*/false, /*1*/false, .... , 
/*'a'*/true, /*'b'*/false, ... /*'x'*/true, .... };

public static boolean hasValue(byte value) {
     return invValues [value & 0xFF];

 }

(Bom, como a tal tabela de valores invertidas ocupa 256 posições - não sei se 256 bytes ou 1 KByte), então até seria possível que ela ficasse em cache, depois de algumas vezes que essa rotina hasValue fosse acessada.

Se tiver paciência, pode-se usar um “java.util.BitSet”, que faz com que a tal tabela de valores invertidos ocupe apenas 256 bits. Não sei se isso é mais rápido; só testando.

import java.util.BitSet;
class TesteBitSet {
    static BitSet bs;
    static {
        bs = new BitSet(256);
        bs.set ('a');
        bs.set ('x');
        bs.set ('d');
        bs.set ('y');
    }
    
    public static boolean hasValue(byte value) {
        return bs.get (value & 0xFF);
    }
    public static void main(String[] args) {
        System.out.println (hasValue ((byte)'a'));
        System.out.println (hasValue ((byte)'b'));
    }
}
M

concordo com o thingol, acredito que essa seja a maneira mais rapida

T

Não sei se é a maneira mais rápida. Só testando - fazendo um benchmark. Hoje em dia os processadores estão tão rápidos que às vezes compensa mais fazer um monte de comparações que ter uma tabela grande em memória.

E de qualquer maneira, se em vez de um byte quiséssemos encontrar uma substring, poderíamos usar algum daqueles algoritmos, como o Boyer-More-Horspool ou outra coisa qualquer.

saoj

É isso aí mesmo! :slight_smile: Mas não precisa de BitSet não !!!

Como byte só tem 256 posições, então acho que compensa e muito.

E se for só standard ascii vc pode usar 128 posições e cortar o 0xFF. (Se o cara passar caracter acima de 128 vai explodir!)

A questão que não quer calar é, como o Java faz indexação de um array em memória ??? Não tenho idéia… Deve ir direto no valor, ou seja, mais rápido impossível…

private static final byte[] values = { 'a', 'x', 'd', 'y' };

private static final boolean[] lookup = new boolean[256];

static {

    for(int i=0; i<values.length;i++) {

        lookup[values[i] & 0xFF] = true;
    }
}

 public static boolean hasValue(byte value) {

      return lookup[value & 0xFF];
 
  }
T

a) Os arrays em Java são realmente contíguos em memória, portanto achar uma posição é um simples cálculo de endereços. Na verdade, enquanto está rodando em modo interpretado, o Java checa também se o índice é positivo e inferior ao limite superior (dimensão). Se estiver fora dos limites, deve dar uma exception (ArrayIndexOutOfBoundsException se não me engano).
b) Se o “just-in-time compiler” conseguir verificar que nunca vai passar dos limites, então essa verificação é removida.
c) Como disse antes, se a tabela for suficientemente pequena, ela vai ficar em cache e seu acesso será bastante rápido. Se ela for muito grande, a rotina vai ficar muito tempo acessando a memória principal (lenta), em vez de pegar valores do cache (que é mais rápido).

saoj

Qual a diferença de memória principal e cache ? Esse cache é do processador ? Porque acessar memória principal é lento ? É mais lento que o cache do processador, mas é rápido pra caramba tb.

De qualquer forma vai ser muitas vezes mais rápido que for loop, concorda? Quando maior o número de opções em values, mais rápido fica.

Criado 24 de agosto de 2006
Ultima resposta 24 de ago. de 2006
Respostas 8
Participantes 4