Performance em toString

15 respostas
J

Tenho uma aplicação applet que se degrada à medida que vai aumentando a quantidade de itens tratados. Até uns 2.000 a 3.000 itens tratados o tempo de resposta me parece normal, levando no total menos de 3 minutos, incluindo outras funções, mas a partir de 3.000 degrada, por exemplo com 20.000 itens o tempo se aproxima de 90 minutos.

Eu suponho que o problema esteja no toString, conforme alguns testes que eu fiz, mas não domino bem Java, sou um aprendiz.

Ficaria muito grato se alguém conseguisse resolver esse problema, pois já batalhei bastante nele, incluindo pesquisas na internet, e nada consegui.

O código desta parte que falo, basicamente, é o que segue:

int apok[][] = new int [600000][17];

StringBuffer dadosn = new StringBuffer();

for(int x = 1; x<selg + 1;x++){
                if  (apok[x][1] != 0 & apok[x][0] != 1)
                {    
                dadosn = dadosn.append("_");
                for(int y = 1; y<jgporccm1;y++){
                dadosn = dadosn.append(apok[x][y]);
                }
                }
                }

dadosw = dadosn.toString();

dadosw = URLEncoder.encode(dados,ISO8859-1) + = +URLEncoder.encode(dadosw, ISO8859-1);

URLConnection con = (URLConnection) urlc.openConnection();

con.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(con.getOutputStream());

wr.write(dadosw);

wr.flush ();

new BufferedReader(new InputStreamReader(con.getInputStream()));
wr.close();

15 Respostas

CristianPalmaSola10

Primeiro quando for posta codigo aqui no forum faça usa da tag code

segundo explique o que voce tem, que tipo de objeto propriedades e o que voce precisa jogando codigo ai ninguem vai adivinha naum temos bola de cristal bele…

J

Cristian,

A questão envolve apenas um applet que tem uma montagem de um enorme string por meio de StringBuffer e append e depois tem que ser passado para toString para haver a devolução para internet.

Nem precisaria código para explicar esta situação, eu coloquei o código só para ficar mais fácil.

Até o término da montagem do string com o append o processamento é rápido, a partir do toString fica muito lento e minha suspeita é de que o toString degrada à medida que aumenta o tamanho do string a ser tratado, neste caso, gostaria de saber se haveria alguma alternativa de solução.

Mas posso estar enganado em minha suspeita e o problema ser na devolução para a internet de um dado tão grande, a degradação pode estar aí.

O restante do código, que é muito grande, não tem nenhuma relação com o problema mencionado, dai eu não ver necessidade de colocá-lo, pois só iria dificultar a compreensão da questão.

De qualquer forma, eu agradeço a sua atenção ao caso, feita em tempo bastante rápido, pois postei na madrugada e vc respondeu logo em seguida.

darklordkamui

o metodo toString não gera delay de performace… dependendo do que vc for fazer…
o que ta deixando seu codigo pesado e lento é o IO… e seu for… que é uma matriz…
o toString só iria deixar lento o procesamento se voce toda hora for gerar um system.out.println … mas mesmo assim seria pouca coisa a más…

que tao vc dividir o seu programa em sub rotinas? isso pode melhorar…

J

darklordkamui,

Realmente o toString funciona bem, enquanto estou convertendo até cerca de 50 mil posições, ou um pouco menos, mas quando passa de 50 mil, e eu tenho aplicações que chegam a mais de 500 mil posições no string para serem convertidas, aparentemente há degradação.

O array não causa delay. Eu já testei de várias formas e a única forma que o delay some é quando eu forço que o string seja menor, assim:

eu monto o array normalmente, digamos que com 200 mil posições e até aqui não há delay

depois eu passo para o toString não o array em si, mas um outro string, menor, de 20 mil posições, neste caso ele não gera delay, mas se eu passar as 200 mil posições do array para o toString o delay aparece.

Sim, realmente a degradação também pode ser na devolução dos dados para a internet e não no toString, mas eu não consegui testar isto separadamente, pois para devolver para a internet eu tenho que, obrigatoriamente, fazer o toString, exceto se houver alguma outra forma que eu desconheça, mas já procurei um bocado e nada achei a respeito.

Agradeço a sua colaboração.

E

Pergunta. Por que é que você escreve uma string gigante de uma vez no OutputStreamWriter, em vez de escrever a string em vários pedaços?

J

entanglement,

Pergunta pertinente.

Eu tentei quebrar em vários pedaços e fazer um toString para cada pedaço, para evitar a eventual degradação, mas depois eu teria que juntar estes pedaços e já não poderia mais ser com StringBuffer e o append com string normal iria deixar tudo mais lento ainda.

Eu fiz esta tentativa e não exatamente a que vc disse, que seria passar aos poucos para o OutputStreamWriter, porque eu teria que fazer mudanças significatiivas na função que iria receber os dados, ao eles serem parciais.

Além disso, como eu ainda desconfio que seja o toString e não a passagem para a internet, estou tentando alguma solução que evite o toString, mas o append de string é terrível de lento, então não posso usar string direto, tenho que usar o StringBuffer e depois o toString.

Suponho que a solução ideal para mim seria conseguir montar este string sem precisar do toString, mas ela não pode ser por meio de append em string, pois demora mais ainda.

Agradeço a sua colaboração.

darklordkamui

acredito que ele ta concatenando tudo do array… faz um teste que calcula o tempo de processamento ate antes de fazer o IO… e depois faz outro só no IO e ve quem ta demorando mais…

estou no aguardo

J

entanglement,

É uma boa idéia, eu vou fazer esse teste porque ele irá caracterizar onde está o gargalo, mas eu já estava de saída, quando chegou sua mensagem, então só poderei fazer na parte da tarde.

darklordkamui

JEOV:
entanglement,

É uma boa idéia, eu vou fazer esse teste porque ele irá caracterizar onde está o gargalo, mas eu já estava de saída, quando chegou sua mensagem, então só poderei fazer na parte da tarde.

tudo bem… quando der posta ai o resultado

D

Every string buffer has a capacity. As long as the length of the character sequence contained in the string buffer does not exceed the capacity, it is not necessary to allocate a new internal buffer array. If the internal buffer overflows, it is automatically made larger. As of release JDK 5, this class has been supplemented with an equivalent class designed for use by a single thread, StringBuilder. The StringBuilder class should generally be used in preference to this one, as it supports all of the same operations but it is faster, as it performs no synchronization.

Esta no proprio java doc do StringBuffer… ou seja

tente usar o StringBuilder para ver se tem resultado!!

darklordkamui

olhando a documentação do StringBuilder realmente parece ser uma boa alternativa…

P

Se nao vai ter varias threads utilizando o buffer, utilize StringBuilder que promete ser mais rapido.
Outra coisa que vc pode fazer eh utilizar o contrutor StringBuilder(int capacity) para especificar um tamanho inicial e evitar que o StringBuffer precise aumentar seu tamanho dinamicamente.

J

É, após colocar contador de tempo em várias partes do programa e rodar com diferentes cargas para tentar identificar alguma degradação, não encontrei nenhuma instrução que estivesse degradando e o toString realmente é inocente, ele não gasta tanto quanto eu pensava. Também o OutputstreamWriter é inocente, não compromete o desempenho.

O problema estava mais em buscar uma otimização do código em diversas pequenas partes antes de começar a montar o string no array e com isto eu consegui reduzir o tempo de processamento para cerca de 1/3 do que estava, o que para mim já está bom, por ora, mas futuramente tentarei conseguir melhorar isto.

Nas pesquisas que fiz na internet acabei achando uma página muito boa sobre desempenho/performance em Java, útil para quem está começando, como eu, e repasso aqui: http://www.inf.ufrgs.br/gppd/disc/inf01008/trabalhos/sem01-1/t2/PDPT2Claus/Performance_JavaIO.htm

Agradeço bastante a ajuda de todos, principalmente a sugestão de cercar as partes com controle de tempo, que acabou encaminhando a solução, era uma ação natural, mas na minha “perseguição”, meu foco no toString, não pensei nisso.

ViniGodoy

Por favor, use a tag code para deixar seus códigos formatados:

Por que você usa StringBuffer no lugar do StringBuilder?

Outra dúvida… Já rodou um profiler na sua aplicação? Antes de conjecturar sobre performance, seria bom descobrir onde realmente está o gargalo da aplicação.
Se não rodou, teste o jvisualvm. Ele já está no diretório do SDK.

J

ViniGodoy,

OK, em alguma eventual próxima vez que utilizar código, eu o farei formatado, pois parece que é algo importante aqui, já que vc é a segunda pessoa a mencionar isto.

Eu comecei usando string, mas a lentidão do append era enorme, então passei para o StringBuffer, o que melhorou muito e quando conheci o StringBuilder fiz um teste com ele. No meu caso não deu diferença de tempo e como eu teria que trocar um pelo outro em 24 programas diferentes (com cerca de 8.000 linhas de código cada, mas poucas diferenças entre os programas, que são 6x4 versões), achei melhor ficar como estava.

A minha aplicação é em PHP (cerca de 300 páginas, no total, originadas em 1998), a parte Java é apenas uma pequena parte dela, por isto nunca me dediquei muito ao Java, também por falta de tempo, pois em meu trabalho eu bato o escanteio e vou para a área cabecear.

A suspeita de performance sobre o toString foi precipitada, realmente, mas foi influenciada pela péssima performance do string com append e os comentários correlatos, em diversas páginas consultadas via Google, sobre a lentidão do Java no trato de string, de forma geral.

Java é apenas uma pequena parte de minha atividade, na qual eu tento aprender somente o estritamente o necessário, por isto não fiz aprofundamentos no SDK.

Para vc tentar entender melhor a minha situação, eu tenho 59 anos, desde 1972 trabalho em informática, Java talvez seja a minha décima linguagem de contato, ou mais (Cobol, Natural, RPG, Mumps, Basic, PHP, VB, Java, nem me lembro de outras), então é fácil pegar o feijão com arroz de qualquer linguagem, mas não tenho tempo de me aprofundar em uma linguagem que pouco utilizo e Java é uma linguagem muito ampla, com muitos propósitos, portanto com um universo de aprendizagem enorme.

Criado 11 de dezembro de 2012
Ultima resposta 13 de dez. de 2012
Respostas 15
Participantes 7