Alta performance com threads

9 respostas
B

Bom dia pessoal.

Estou com um trabalho de fazer um serviço (aplicativos rodados em background a partir do console, iniciados pelo cron) que vai carregar alguns arquivos e distribuir seus dados em várias tabelas do banco.

Ele já está funcionando, porém acho que um pouco lerdo demais. Dessa forma decidi implementá-lo com threads.

O que estou programando no momento é ele pegar o grupo de arquivos, dele tirar um grupo de linhas relacionadas, manda-lo para classes parsers dos arquivos e finalmente pegar o resultado e criar uma thread que vai salvar no banco.

Bem, daí surgem vários problemas. Tenho que controlar o número de threads ou sofro de OutOfMemoryError. Também tenho que controlar o número de conexões abertas pois o banco já está trabalhando no limite.

Sobre o primeiro planejei da seguinte forma:

package threads;

import java.util.Random;

public class ExemploProcessadores
{
    static int count = 0;

    public static void main(String[] args)
    {
        ExemploProcessadores main = new ExemploProcessadores();
        main.executar();
    }

    public void executar()
    {
        ThreadGroup tg = new ThreadGroup("PROCESSADORES");
        while (true)
        {
            if (tg.activeCount() > 25)
            {
                synchronized (this)
                {
                    try
                    {
                        wait();
                    }
                    catch (InterruptedException ex)
                    {}
                }
                System.out.println("Continuando... " + tg.activeCount() + " - " + count);
            }
            
            Thread proc = new Thread(tg, new Processador());
            proc.start();
        }
    }

    class Processador extends Thread
    {
        public void run()
        {
            try
            {
                sleep(new Random().nextInt(10) * 1000);
            }
            catch (InterruptedException ex)
            {}
            count++;
            notify();
        }
    }
}

Eu paro a criação de novas threads contando quantas já estão ativas. Quando alguma thread me nottificar que ela terminou de processar, eu retomo. Bem, do jeito que está não funciona. Eu não sei como acordar threads devidamente.

Para funcionar, tenho que colocar wait com algum valor, como wait(1000); e retirar o notify() ou o notifyAll() da thread. Com um valor suficientemente alto de threads até que ele vai bem (não para).

Agora para o segundo problema, não achei solução ainda. Gostaria de reaproveitar a thread(a conexão que passei para ela). Algo como "quando o processamento deste lote acabar, notifico alguém para me fornecer mais dados para trabalhar, e então continuo".

Sugestões?

Ahhh! Um detalhe pequeno: Tem que rodar em Java 1.4. :lol:

9 Respostas

J

Me desculpem se eu estiver errado, não manjo muito :smiley: … mas quanto ao segundo problema, de reaproveitar a conexão aberta, se você criar um pool de conexões, ele não faria isso pra você?

C

Algumas perguntas:

  • Nao entendi o que exatamente estava deixando o processo lerdo? acesso ao banco de dados?

  • Nao entendi porque decidiu implementar com threads, existe algum requisito (que nao seja performance) que exija um processo em paralelo? O que impede processar um arquivo por vez.

  • Esse worflow é algum tipo de scraping?

T

Se puder usar as classes de java.util.concurrent, que têm recursos como pool de threads e outras coisas parecidas, não é melhor? Usar “threads” “cruas” (você mesmo fazendo o join, wait etc.) é como programar com goto’s. É possível mas dentro da medida do possível deve ser evitado, já que é extremamente complicado controlá-las corretamente.

Gobain

Se vc pudesse fazer em 1.5 poderia usar o java.util.concurrent.ExecutorService pra gerenciar o nº de threads…

ExecutorService pool = Executors.newFixedThreadPool(50);
B

cmoscoso:
- Nao entendi o que exatamente estava deixando o processo lerdo? acesso ao banco de dados?

  • Nao entendi porque decidiu implementar com threads, existe algum requisito (que nao seja performance) que exija um processo em paralelo? O que impede processar um arquivo por vez.

  • Esse worflow é algum tipo de scraping?


Não fiz um profiling da aplicação, acho que não posso dizer que ele está lerdo. Só gostaria que ele fosse mais rápido. Qualquer coisa que deixe um processamento de milhões de linhas mais rápido, dentro dos limites, é bem vindo.

Já estou processando um arquivo por vez. Quero processar o mesmo arquivo mais rápido. Pensei em threads por que é padrão os nossos serviços usarem eles para aumentar o processamento.

O que é Scraping?

thingol:
Se puder usar as classes de java.util.concurrent, que têm recursos como pool de threads e outras coisas parecidas, não é melhor? Usar “threads” “cruas” (você mesmo fazendo o join, wait etc.) é como programar com goto’s. É possível mas dentro da medida do possível deve ser evitado, já que é extremamente complicado controlá-las corretamente.
[quote=Gobain]Se vc pudesse fazer em 1.5 poderia usar o java.util.concurrent.ExecutorService pra gerenciar o nº de threads…

ExecutorService pool = Executors.newFixedThreadPool(50);

java.util.concorrent só existe a partir do Java 5. Vou pedir autorização para usar ele no serviço, já que o 1.4 é mais problema de servidores web o e nosso conteiner.

T

Se não conseguir a autorização, use as classes originais do Doug Lea, em http://g.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
ou então o backport em http://backport-jsr166.sourceforge.net/index.php

C

Bruno Laturner:
Não fiz um profiling da aplicação, acho que não posso dizer que ele está lerdo. Só gostaria que ele fosse mais rápido. Qualquer coisa que deixe um processamento de milhões de linhas mais rápido, dentro dos limites, é bem vindo.

Já estou processando um arquivo por vez. Quero processar o mesmo arquivo mais rápido. Pensei em threads por que é padrão os nossos serviços usarem eles para aumentar o processamento.

O que é Scraping?

Minha atual definicao é o processo de extrair informacoes de um sistema e usalo para alimentar outro sistema que fara uso dessa informacao num contexto diferente do original.

Perguntei porque me pareceu ser o mesmo padrao de processo mas com a necessidade de alta performance no processamento.

B

Pelo que entendi da definição, acho que não é scraping não. Seria gerar objetos intermediários cujo processamento é mais rápido?

Voltando ao assunto, fiz uns testes com threads e sem (bem… uma p/ ser exato).

Sem threads está ganhando de lavada. O com threads ainda teve o bônus de derrubar a base de testes. tsk.

Acho que a culpa é o meu controle ineficiente de numero de threads ativas. No momento estou realizando os testes monothread, com um modelo bem mais simples de processamento.

thingol: Obrigado pelos links! Acho que não vou utilizar essas libs no momento, mas vai servir de estudo para um super-projeto ainda maior que está por vir.

C

Bruno Laturner:
Pelo que entendi da definição, acho que não é scraping não. Seria gerar objetos intermediários cujo processamento é mais rápido?

Voltando ao assunto, fiz uns testes com threads e sem (bem… uma p/ ser exato).

Sem threads está ganhando de lavada. O com threads ainda teve o bônus de derrubar a base de testes. tsk.

Acho que a culpa é o meu controle ineficiente de numero de threads ativas. No momento estou realizando os testes monothread, com um modelo bem mais simples de processamento.

thingol: Obrigado pelos links! Acho que não vou utilizar essas libs no momento, mas vai servir de estudo para um super-projeto ainda maior que está por vir.

Nao, seria parsear de um lugar pra jogar eem outro, mas geralmente num contexto de aplicacoes web.

Bem, entao voltando ao assunto, vc so precisa trabalhar no nivel de lock de objetos naqueles objetos que representam recurso compartilhados. Pela sua descricao do servico nao parece ser o caso do arquivo (ja que dele sera lido) mas talvez de algum service que coordenara o parser ja que varias threads vao querer processar o conteudo do arquivo simultaneamente. O banco de dados tb sera compartilhado mas aqui ja existem muitas solucoes (o mesmo vale para o pool de threads que eu pesquisaria por algo pronto).

Em relacao ao pool de threads, comecar perguntando como as threads sao criadas nao me parce um bom sinal num estagio inicial da evolucao para um sistema multithread. O OutOfMemoryError que recebeu provavelmente tem mais a ver com o codigo “de negocio” (como o servico de parser reage quando 50 threads lhe pedem um trecho do arquivo) do que com a forma de criacao das threads.

Criado 16 de outubro de 2008
Ultima resposta 18 de out. de 2008
Respostas 9
Participantes 5