Agendando algumas tarefas intensivas da CPU

5

Eu preciso agendar um pequeno número de tarefas intensivas de CPU para executar de vez em quando, lendo de dados compartilhados e gravando em buffers dedicados. Eu não necessariamente quero rolar meu próprio agendamento, mas não tenho certeza se as bibliotecas como o Quartz são apropriadas para essa pequena escala. Estou usando o Java 8 em um ambiente de servidor, mas com nós isolados e não importa se algumas iterações são perdidas de vez em quando.

Detalhes do problema:

Eu tenho 5 buffers de dados de dados binários para processar. Antes de processar cada buffer, aloco um destino vazio e a função grava nesse destino. Cada buffer precisa ser processado em uma programação diferente com uma função diferente, embora todas as funções possam manipular a falta de uma iteração e calcular o dobro na próxima execução.

O primeiro buffer é ~ 30mb e demora ~ 200ms para processar, e precisa ser processado a cada 500ms. O restante está em torno de ~ 6mb cada e leva ~ 50ms para processar e precisa ser processado a cada 1000ms.

As funções de processamento só devem gravar no buffer de destino e são sem estado, mas podem ler qualquer um dos buffers existentes. O processo inteiro terá pelo menos seu próprio segmento e pode ter vários segmentos. Nada disso é crítico, não será armazenado em cluster e será mantido quase exclusivamente na memória.

Exemplo:

Uma implementação bastante burra pode ser:

for (layer in parent.layers) {
    new thread(() => {
        while (true) {
            buffer = new int[layer.data.length]
            process(layer.data, buffer, parent)    // remember, this can access other layers
            layer.data = buffer
            sleep(layer.increment)
        }
    }
}    

A execução de cada camada em seu próprio segmento torna o processamento bastante simples, desde que nada no meio esteja bloqueado. Agarrar cada camada com a qual a função de processamento se preocupa quando começa uma iteração e liberá-las no final deve funcionar, uma vez que elas são somente leitura e não estou preocupado com outro thread que substitua a referência.

Pergunta:

  1. Há algum problema com os Timers para esse tipo de trabalho? Eles fornecem uma maneira de descartar ou aguardar a iteração anterior?
  2. Quartz é uma escolha viável, ou simplesmente absurda?
  3. Pode algo tão simples como System.nanoTime ser suficiente nessa precisão?
por ssube 11.08.2014 / 21:35
fonte

1 resposta

1

Usar um único Timer e um ExecutorService ilimitado (pool de threads) para esse tipo de agendamento de propósito geral pode ser muito poderoso. No entanto, ele não interrompe a execução simultânea da tarefa, caso a invocação anterior ainda não tenha sido concluída.

Combinamos Timer e ExecutorService apenas para esse propósito, junto com a capacidade de restringir o número de tarefas simultâneas com base no número de CPUs disponíveis para o sistema (apropriado para tarefas ligadas à CPU):

link

Para interromper a invocação simultânea apenas com essas duas ferramentas, você precisará reverter sua própria proteção.

Eu resolvi esse problema recentemente criando um "ConcurrencyLimiter" que serializará o acesso a um pedaço arbitrário de código / recurso dado um objeto de chave arbitrária. Se um segundo thread tentar executar a mesma tarefa, ele simplesmente aguardará e usará o resultado do primeiro encadeamento. Assim, a concorrência é evitada e ambos os encadeamentos obtêm uma resposta significativa.

link

No que diz respeito à limitação de simultaneidade no próprio agendador de tarefas, há também uma implementação Java simples e simples do cron que permite evitar a execução simultânea e manipula todo o agendamento:

link

Fonte em link (depende de link ) e link Todos LGPLv3 e livre para o mundo, sem dependências externas e Java 1.6 +.

O ponto aqui não é ligar meu próprio código. Eu só quero ressaltar que você pode lidar com isso no nível de agendamento ou dentro da tarefa em si.

Desculpe - perguntas vagas recebem respostas vagas.

    
por 30.01.2015 / 19:58
fonte