Estou começando a estudar a API NIO, sem nenhuma necessidade especifica, apenas para ganhar conhecimento…e para conferir sua melhor performance em relação a java.io.
Porém no primeiro exemplo básico que fiz, fiquei decepcionado achei que a performance seria muito melhor que a mesma implementação com java.io.
O primeiro teste que fiz foi uma simples leitura (que quase todo sistema faz) de um arquivo texto de 500MB e a diferença de performance de uma implementação (NIO) e outra (java.io), não foi tão grande.
Pq?
Minha implementação esta com problemas?
O ganho de performance seria apenas para processos mais complexos, como leitura/escrita, acesso randomico, sockets thread-safe, etc ?
Em termos de performance, o FileChannel não é tão superior aos Streams. Acho que ele foi inserido principalmente para facilitar o trabalho com os sockets, além de dar mais uniformidade ao código.
Se seu objetivo é testar a performance, eu evitaria também usar um charsetDecoder e métodos como indexOf() no seu “microbenchmark”.
Claro, usando o FileChannel você ainda tem as vantagens dos Buffers, como poder escolher qual tipo de byte order (Little ou Big endian) você quer usar, o que pode ser útil em comunicações com aplicações não-java. Tem também os MemoryMappedFiles, que podem ser úteis para acessos não bloqueantes aos arquivos. Finalmente, tem ainda os métodos transferTo e transferFrom, que são meios bastante otimizados de copiar dados entre canais. Nesse caso, existe ganho de performance, mesmo no FileChannel.
No caso do Socket, você pode usar Selectors para, com menos threads, aumentar o throughput e a performance de sua aplicação. Foi o ponto do java.nio onde fiquei realmente impressionado, e onde as vantagens não mais perceptíveis.
Mas para ler ou gravar arquivos-texto normalmente não compensa; é melhor, nesse caso, usar um BufferedReader e modificar o tamanho do buffer, que é passado via parâmetro (por exemplo, em vez de usar os 8KB normais, usar um pouco mais).
Se é o caso de alterar o charset, use o InputStreamReader / OutputStreamWriter, que recebe um nome de charset como parâmetro.
Ele é interessante para os casos que o Louds citou.
[quote=thingol]Mas para ler ou gravar arquivos-texto normalmente não compensa; é melhor, nesse caso, usar um BufferedReader e modificar o tamanho do buffer, que é passado via parâmetro (por exemplo, em vez de usar os 8KB normais, usar um pouco mais).
Se é o caso de alterar o charset, use o InputStreamReader / OutputStreamWriter, que recebe um nome de charset como parâmetro.
Ele é interessante para os casos que o Louds citou.
[/quote]
Thingol,
Se usar o BufferedReader/Writer provavelmente o cara ver ter que usar Input/OutputStreamReader.
Outra coisa, tem que tomar cuidado com o tamanho do buffer, valores muito altos começam a fazer um efeito inverso, ou seja, a leitura (principalmente) e escrita começam a ficar lentas. Acredito que tenha que testar caso a caso, mas quando precisei buffer de 256K foram os que me deram melhor resultado.
Realmente é caso a caso. Uma vez tinha feito um teste boboca e para o meu problema em particular, usar mais que 8K não acelerava o processamento. Depende de várias coisas (velocidade do disco, cache do disco, de memória etc.)
E…contradizendo o que disse a implementação com NIO é bem mais rápido,
realizei um teste de leitura com um arquivo de 1Gb e a leitura com NIO foi 3,3 X mais rápida.
Arquivo texto com 1Gb java.io - Tempo de leitura: 31797 ms
java.nio - Tempo de leitura: 9359 ms
Agora com um arquivo pequeno 7Mb… java.io - Tempo de leitura: 250 ms
java.nio - Tempo de leitura: 78 ms
Concluo que se o sistema manipula arquivos gigantes ou tem que manipular centenas de arquivos em um curto período deve-se usar o NIO sim, para ler arquivos texto ou não…, caso o sistema não tenha estas caracteristicas, tanto faz java.io com java.nio, com preferencia para java.io por ser mais simples (eu acho).
Ahh…este foi um simples teste despretensioso que fiz, não considerei outros N fatores como consumo de CPU, memória, SO, etc…
Certa vez, tivemos que trocar nossos serviços socket do IO para o NIO. O problema era que os pacotes de IO não sabem informar com certeza se o socket ainda estava conectado. Resolvemos esse problema usando o NIO. Mto mais exato no método isConnected().