Fiz um programinha para ler um arquivo e inserir no banco, e funcionou tudo certo, só que meu arquivo é muito grande então estava demorando muito para inserir no banco optei em fazer ele com thread e vai bem mais rápido, só que após algum tempo rodando ele da o seguinte erro:
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:597)
at Main.main(Main.java:46)
Ta claro pela mensagem que o java comeu toda a memória que ele tinha, mas gostária de saber como poderia fazer para controlar isso, para ele não abrir mais threads do que o computador suporta ?
Voce disse que criou uma thread para rodar em background e ler seu arquivo, enquanto isso vc nao precissa para de usar sua aplicacao, certo ?
Nao era para ocorrer este erro. Tem como postar o codigo que vc criar a thread e o q a thread esta executando ?
M
marcelogomesrp
O Main
No main estou usando o BioJava para fazer o parser do arquivo, para cada linha do arquivo abro um thread para fazer o insert no banco.
Já que você está criando uma Thread para cada linha do arquivo, certamente haverá problema se o arquivo for grande demais, pois o excesso de threads irá consumir toda a memória disponível da JVM. Há uma discussão interessante sobre isso no link abaixo:
Então, acho que seria interessante você limitar o número máximo de threads simultâneas. Em ambiente Windows, por exemplo, a recomendação é usar até cerca de 16 threads ao mesmo tempo.
S
sandeco
que tal um sleep(tempo) na thread?
M
marcelogomesrp
Roger,
Esta quantidade de thread teria que ser fixa ? como saber o máximo que poderia usar ? Sabe de algum design pattern para trabalhar com threads neste esquema ?
Obrigado,
Marcelo Gomes
M
marcelogomesrp
Sandeco.
Não entendo pq usar o sleep poderia me ajudar, ele só não vai mandar a thread dormir por um tempo X ??? a thread mesmo dormindo iria ficar segurando a memória não eh ?? e meu sistema ia ficar mais lento pois iria ficar dormindo x tempo.
Obrigado,
Marcelo Gomes
R
roger_rf
Sim, sugiro usar um valor fixo para o número máximo de threads simultâneas. Já enfrentei o seguinte problema: para emitir um relatório, tinha de realizar 4 consultas SQL para cada mês solicitado, e em seguida conciliar via programação os dados retornados pelas consultas. Assim, se o relatório precisasse cobrir um ano inteiro, portanto 12 meses, tinha de executar 12 x 4 = 48 consultas SQL no total. Executar todas estas consultas uma após a outra demorava muito, e se executasse todas ao mesmo tempo certamente derrubaria o desempenho do servidor de Banco de Dados. Para resolver o problema, criei uma classe de thread para executar uma única consulta SQL. Para 48 consultas, tínhamos portanto 48 threads. Então, criei uma outra classe de thread para arbitrar a execução destas 48 threads, de modo que não mais do que 3 delas executassem ao mesmo tempo. Quando uma das threads SQL encerrava a execução, a thread árbitra era notificada, e portanto podia disparar uma outra thread SQL. O desempenho do relatório melhorou muito e não tive de torturar (muito) o servidor de Banco de Dados.
M
marcelogomesrp
Entendi, tem como me dar uma dica de como fazer este controle do numero de threads?
Obrigado,
Marcelo Gomes
V
vdb
Uma solucao simples para vc testar seria, coloque uma variavel int static na classe da thread, incremente 1 a cada start, e dentro do while so execute o bloco de codigo se a variavel for < 16, q seria a quantidade de threads q deseja executar, e apos a linha Sequencia sequencia = serquenciaService.Salvar(getSequenciaArquivo()); subtraia 1 do contador. Lembre-se de criar metodos para manipular a variavel sincronizados.
Desta forma vc pode verificar se o desempenho é o esperado…
M
marcelogomesrp
Funcionou…
na classe insert criei a variavel quantidade como static.
ExecutorServicepool=Executors.newFixedThreadPool(QUANTIDADE_DE_THREADS_QUE_DESEJA);while(stream.hasNext()){org.biojava.bio.seq.Sequenceseq=stream.nextSequence();SequenciasequenciaArquivo=newSequencia();sequenciaArquivo.setNome(seq.getName());sequenciaArquivo.setSequencia(seq.seqString());pool.execute(sequenciaArquivo);//considerando que essa classe Sequencia implemente Runnable}pool.shutdown();
[]´s
M
marcelogomesrp
Ficou perfeito… ou quase …
Por tentativa e erro cheguei no número mágico de 1000 threads rodando ao mesmo tempo, teria alguma forma matematica de descobrir quantas thred o sistema iria conseguir rodar ao mesmo tempo ?
Mas uma vez muito obrigado mesmo!!! vocês são fera!!!
V
vdb
1000 threads eh coisa em, as vezes o aumento do numero de threads nao reflete no aumento de velocidade. Seria interessante vc verificar o tempo q 1000 threads leva para ler seu arquivo, e depois baixe para 500 e faca o mesmo teste. Ja tive aplicações q coloquei 100 threads para rodar e foi mais lento do q deixar 20.
R
roger_rf
Reforço o comentário do vdb e sugiro que, se for importante para você experimentar vários valores para a quantidade máxima de threads simultâneas, pode ser interessante obter essa quantidade a partir de um arquivo de configuração.
M
marcelogomesrp
ok, vou gerar os valores para 1000, 500 e 100 e posto aqui
obrigado,
Marcelo Gomes
D
Dieval_Guizelini
Olá Marcelo,
o seu problema me interessou mais pelo fato de você estar utilizando a biblioteca biojava do que pelas questões de thread.
Por um acaso você sabe me dizer se o desempenho dela é comparável com bioperl ou biopython? Você está utilizando ela para montar genomas?
Com relação ao seu problema, eu acho que a questão não se resolve simplesmente aumentando o número de threads, mas identificando onde o gargalo está ocorrendo. Pelo seu código, posso sugerir duas opções:
Na parte de acesso ao arquivo, utilize buffer, algo como:
Outro ponto, se você criar uma classe (thread tb) que tenha uns 5 ou 10 objetos (5 ou 10 threads) consumindo uma fila de objetos a serem inseridos no banco, e utilizar o preparedstatement ao invés do jpa, certamente será mais rápido. Outra possibilidade seria tentar utiliza a atualização em batch: http://java.sun.com/j2se/1.3/docs/guide/jdbc/spec2/jdbc2.1.frame6.html