Pergunta

Eu quero obter a perspectiva da comunidade sobre isso. Se eu tenho um processo que é fortemente encadernado db/io, quão inteligente seria para paralelizar os caminhos de processo individuais usando a biblioteca paralela da tarefa?

Vou usar um exemplo ... se eu tiver um monte de itens e preciso fazer as seguintes operações

  1. Consulte um db para uma lista de itens
  2. Faça algumas operações de agregação para agrupar determinados itens com base em uma lista dinâmica de parâmetros.
  3. Para cada resultado agrupado, consulte o banco de dados para algo baseado no resultado agregado.
  4. Para cada resultado agrupado, faça alguns cálculos numéricos (3 e 4 aconteceriam sequencialmente).
  5. Faça algumas inserções e atualizações para o resultado calculado no #3
  6. Faça algumas inserções e atualizações para cada item retornado em #1

Logicamente falando, posso paralelizar em um gráfico de tarefas nas etapas #3, #5, #6, pois um item não tem influência no resultado do anterior. No entanto, cada um deles estará esperando no banco de dados (SQL Server), o que é bom e eu entendo que só podemos processar até onde o servidor SQL nos deixará.

Mas quero distribuir logicamente a tarefa na máquina local para que ela processe tão rápido quanto o banco de dados nos permite sem ter que esperar por nada do nosso lado. Eu fiz algum protótipo simulado em que substituo as chamadas de banco de dados por thread.sleeps (também tentei algumas variações com .spinwait, que foi um milhão de vezes mais rápido), e a versão paralela é waaaaay mais rápida que a implementação atual que é completamente serial e não é paralelo.

O que tenho medo de colocar muita pressão no servidor SQL ... Há alguma consideração que devo considerar antes de ir muito longe nesse caminho?

Foi útil?

Solução

Outra opção seria criar um pipeline para que a Etapa 3 para o segundo grupo que acontece ao mesmo tempo que a Etapa 4 para o primeiro grupo. E se você puder sobrepor as atualizações na etapa 5, faça isso também. Dessa forma, você está fazendo acessos e processamento SQL simultâneos, mas não tributando demais o banco de dados, porque você possui apenas duas operações simultâneas em andamento de uma só vez.

Assim, você faz as etapas 1 e 2 sequencialmente (presumo) para obter uma coleção de grupos que exigem mais processamento. Então. Seu tópico principal começa:

for each group
  query the database
  place the results of the query into the calc queue

Um segundo thread atende à fila de resultados:

while not end of data
  Dequeue result from calc queue
  Do numeric calculations
  place the results of the query into the update queue

Um terceiro thread atende à fila de atualização:

while not end of data
  Dequeue result from update queue
  Update database

o System.Collections.Concurrent.BlockingCollection<T> é uma fila muito eficaz para esse tipo de coisa.

O bom aqui é que, se você puder ampliá -lo, se quiser, adicionando vários threads de cálculo ou threads de consulta/atualização se o servidor SQL puder lidar com mais transações simultâneas.

Eu uso algo muito semelhante a isso em um programa diário de mesclagem/atualização, com resultados muito bons. Esse processo específico não usa o SQL Server, mas sim a E/S de arquivo padrão, mas os conceitos se traduzem muito bem.

Outras dicas

Se a versão paralela for muito mais rápida que a versão em série, eu não me preocuparia com a tensão no seu servidor SQL ... a menos que as tarefas que você esteja executando sejam de baixa prioridade em comparação com outras operações significativas ou críticas que também são executado no servidor DB.

Sua descrição das tarefas não é bem compreendida por mim, mas quase parece que mais dessas tarefas deveriam ter sido executadas diretamente no banco de dados (presumo que há detalhes que tornam isso possível?)

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