Como posso dizer a uma máquina multi-core/multi-CPU para processar chamadas de função em um loop em paralelo?

StackOverflow https://stackoverflow.com/questions/56769

  •  09-06-2019
  •  | 
  •  

Pergunta

Atualmente estou projetando um aplicativo que possui um módulo que carregará grandes quantidades de dados de um banco de dados e os reduzirá a um conjunto muito menor por meio de vários cálculos, dependendo das circunstâncias.

Muitas das operações mais intensivas comportam-se de forma determinística e prestam-se ao processamento paralelo.

Desde que eu tenha um loop que itere sobre um grande número de blocos de dados que chegam do banco de dados e para cada um deles chame uma função determinística sem efeitos colaterais, como eu faria para que o programa não esperasse o retorno da função, mas sim defina quais seriam as próximas chamadas, para que pudessem ser processadas em paralelo?Uma abordagem ingênua para demonstrar o princípio me serviria por enquanto.

Eu li o artigo MapReduce do Google e, embora pudesse usar o princípio geral em vários lugares, não irei, por enquanto, focar em grandes clusters, mas sim em uma única máquina multi-core ou multi-CPU para a versão 1.0 .Atualmente, não tenho certeza se posso realmente usar a biblioteca ou se teria que lançar uma versão básica simplificada.

Estou em um estágio inicial do processo de design e até agora estou visando C-alguma coisa (para os bits críticos de velocidade) e Python (para os bits críticos de produtividade) como minhas linguagens.Se houver razões convincentes, posso mudar, mas até agora estou satisfeito com a minha escolha.

Observe que estou ciente do fato de que pode levar mais tempo para recuperar o próximo pedaço do banco de dados do que para processar o atual e todo o processo seria então vinculado à E/S.Eu, no entanto, assumiria por enquanto que não é e, na prática, usaria um cluster de banco de dados ou cache de memória ou qualquer outra coisa que não estivesse vinculada à E/S neste momento.

Foi útil?

Solução

Posso estar faltando alguma coisa aqui, mas isso parece bastante simples usando pthreads.

Configure um pequeno conjunto de threads com N threads e tenha um thread para controlar todos eles.

O thread mestre simplesmente fica em um loop fazendo algo como:

  1. Obtenha um pedaço de dados do banco de dados
  2. Encontre o próximo tópico livre Se nenhum tópico estiver livre então espere
  3. Entregar o pedaço ao thread de trabalho
  4. Volte e pegue o próximo pedaço do banco de dados

Enquanto isso, os threads de trabalho que eles sentam e fazem:

  1. Marcar-me como livre
  2. Aguarde até que o thread do mastro me forneça um pedaço de dados
  3. Processar o pedaço de dados
  4. Marcar-me como livre novamente

O método pelo qual você implementa isso pode ser tão simples quanto dois arrays controlados por mutex.Um contém os threads trabalhados (o threadpool) e o outro indica se cada thread correspondente está livre ou ocupado.

Ajuste N ao seu gosto ...

Outras dicas

Bem, se .net é uma opção, eles se esforçaram muito para Computação Paralela.

Se você ainda planeja usar Python, você pode querer dar uma olhada em Em processamento.Ele usa processos em vez de threads para computação paralela (devido ao Python GIL) e fornece classes para distribuição de "itens de trabalho" em vários processos.Usando a classe pool, você pode escrever código como o seguinte:

import processing

def worker(i):
    return i*i
num_workers = 2
pool = processing.Pool(num_workers)
result = pool.imap(worker, range(100000))

Esta é uma versão paralela do itertools.imap, que distribui chamadas para processos.Você também pode usar os métodos apply_async do pool e armazenar objetos de resultado lento em uma lista:

results = []
for i in range(10000):
    results.append(pool.apply_async(worker, i))

Para referência adicional, consulte a documentação da classe Pool.

Pegadinhas:

  • o processamento usa fork(), então você deve ter cuidado no Win32
  • objetos transferidos entre processos precisam ser selecionáveis
  • se os trabalhadores forem relativamente rápidos, você poderá ajustar o tamanho do bloco, ou seja,o número de itens de trabalho enviados para um processo de trabalho em um lote
  • processamento.Pool usa um thread em segundo plano

Você pode implementar o algoritmo do Google MapaReduzir sem ter máquinas fisicamente separadas.Basta considerar cada uma dessas "máquinas" como "tópicos". Os threads são distribuídos automaticamente em máquinas de vários núcleos.

Se você estiver trabalhando com um compilador que suporte isso, sugiro dar uma olhada em http://www.openmp.org Para uma maneira de anotar seu código de tal maneira que certos loops serão paralelos.

Ele também faz muito mais e pode ser muito útil.

A página deles informa que o gcc4.2 suportará openmp, por exemplo.

O mesmo conjunto de threads é usado em java.Mas os threads em threadpools são serializáveis ​​e enviados para outros computadores e desserializados para execução.

Desenvolvi uma biblioteca MapReduce para uso multithread/multi-core em um único servidor.Tudo é cuidado pela biblioteca, bastando ao usuário implementar Map e Reduce.Ela está posicionada como uma biblioteca Boost, mas ainda não aceita como uma biblioteca formal.Confira http://www.craighenderson.co.uk/mapreduce

Você pode estar interessado em examinar o código de libdispatch, que é a implementação de código aberto do Grand Central Dispatch da Apple.

O TBB ou boost::mpi da Intel também pode ser do seu interesse.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top