0
I’m using the Entity Framework
and Multithreading
on a project C#
and I am going through problems of connection with the SQL Server
.
Well, I wanted to improve the speed of some data searches for a grid because they are very time consuming selects. First I used multithreading in the queries and I saw that it didn’t really matter if I triggered the queries in different threads, because in the bank it ends up lining the queries as if I were in a normal loop. In order to solve this, I started instantiating several new scopes, repositories and connectionstring’s to each trhead I create, so that it selects as if they were different people accessing the database and so run all queries in parallel. It worked, in a way, but when I create many threads in some queries it of problems like The underlying provider failed on open
and Referência de objeto não definida para uma instância de um objeto
, however, it is not always in the same query, it is kind of random. Has anyone ever gone through such a problem or has a solution for it? I am also open to suggestions if there is a better way to do what I am doing. Below is my code:
public void BuscarDadosGridFamilia(string filialSelecionadaCodigo, string familiaSelecionada, string legendaSelecionada)
{
_listaClasseGenericaFamiliaProduto.Clear();
DateTime dataInicialPeriodoVendas = DateTime.Now.AddDays(-30);
DateTime dataFinalPeriodoVendas = DateTime.Now;
_totalVendas30Dias = 0;
_totalEstoqueAtual = 0;
_totalEstoquePrevisto = 0;
_totalCapacidadeMin = 0;
_totalCapacidadeMax = 0;
_totalGiroObj = 0;
decimal _totalGiroAtual = 0;
decimal _totalGiroPrevisto = 0;
decimal _totalGiroCapacidadeMax = 0;
decimal _totalGiroObjetivo = 0;
decimal _totalGiroIdeal = 0;
int _quantidadeTasks = 0;
int _totalLinhasGridFamilia = 0;
string[] filialSplit = filialSelecionadaCodigo.Split('-');
Filial filialSelecionada = _filialAplicacao.RepositorioFilial.ObterPorCodigo(_usuarioAtual.LocalEstoqueAtual.Filial.Empresa, filialSplit[0].Trim());
var _familiaProduto = _familiaProdutoAplicacao.RepositorioFamiliaProduto.Todos()
.Where(d => d.FlagPercentualCapacidadeGondola == 1)
.Where(d => (d.Codigo.StartsWith(familiaSelecionada + ".") || d.Codigo == familiaSelecionada) && familiaSelecionada != "");
if (legendaSelecionada != "Todos")
_familiaProduto = _familiaProduto.Where(d => d.FamiliaMarcadaCapacidadeGondola.LegendaLinha.Legenda == legendaSelecionada.Split('-')[0].Trim());
Task[] tasks = new Task[_familiaProduto.Count()];
foreach (var familia in _familiaProduto)
{
ConexaoBanco.ConexaoMultiThread = "familia-" + familia.Codigo;
string connectionString = ConexaoBanco.GetConexao();
ConexaoBanco.ConexaoMultiThread = "familia-" + familia.Codigo;
IRepositorioEscopo escopo = Havan.Infra.IoC.Container.Obter<IRepositorioEscopo>();
ParametrosTask parametrosTask = new ParametrosTask();
parametrosTask.familia = familia;
parametrosTask.filialSelecionada = filialSelecionada;
parametrosTask.legendaSelecionada = legendaSelecionada;
parametrosTask.repositorioEscopo = escopo;
Task _task = new Task(() => BuscarDadosGridFamiliaTask(parametrosTask), TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);
_task.Start();
tasks[_quantidadeTasks] = _task;
_totalLinhasGridFamilia++;
_quantidadeTasks++;
}
Task.WaitAll(tasks);
try { _totalGiroAtual = Arredondar((_totalEstoqueAtual / _totalVendas30Dias) * 30); }
catch (Exception) { Arredondar(_totalGiroAtual = 0); };
try { _totalGiroPrevisto = Arredondar((_totalEstoquePrevisto / _totalVendas30Dias) * 30); }
catch (Exception) { Arredondar(_totalGiroPrevisto = 0); };
try { _totalGiroCapacidadeMax = Arredondar((_totalCapacidadeMax / _totalVendas30Dias) * 30); }
catch (Exception) { Arredondar(_totalGiroCapacidadeMax = 0); };
try { _totalGiroIdeal = Arredondar((_totalVendas30Dias / 30) * _totalGiroObjetivo); }
catch (Exception) { Arredondar(_totalGiroIdeal = 0); };
try { _totalGiroObjetivo = Arredondar(_totalGiroObj / _familiaProduto.Count()); }
catch (Exception) { Arredondar(_totalGiroObjetivo = 0); };
ClasseGenericaFamiliaProduto _classeGenericaFamiliaProdutoTotal = new ClasseGenericaFamiliaProduto();
_classeGenericaFamiliaProdutoTotal.Filial = "TOTAL:";
_classeGenericaFamiliaProdutoTotal.Vendas30Dias = _totalVendas30Dias;
_classeGenericaFamiliaProdutoTotal.EstoqueAtual = _totalEstoqueAtual;
_classeGenericaFamiliaProdutoTotal.EstoquePrevisto = _totalEstoquePrevisto;
_classeGenericaFamiliaProdutoTotal.CapacidadeMin = _totalCapacidadeMin;
_classeGenericaFamiliaProdutoTotal.CapacidadeMax = _totalCapacidadeMax;
_classeGenericaFamiliaProdutoTotal.GiroAtual = _totalGiroAtual;
_classeGenericaFamiliaProdutoTotal.GiroPrevisto = _totalGiroPrevisto;
_classeGenericaFamiliaProdutoTotal.GiroCapacidadeMax = _totalGiroCapacidadeMax;
_classeGenericaFamiliaProdutoTotal.GiroObjetivo = _totalGiroObjetivo;
_classeGenericaFamiliaProdutoTotal.GiroIdeal = _totalGiroIdeal;
if (_listaClasseGenericaFamiliaProduto.Count > 0)
_listaClasseGenericaFamiliaProduto.Add(_classeGenericaFamiliaProdutoTotal);
gridFamilia.DataSource = _listaClasseGenericaFamiliaProduto;
}
And now the method that is called by Tasks
which contain consultations with the bank by LINQ
public void BuscarDadosGridFamiliaTask(ParametrosTask _parametrosTask)
{
decimal _estoqueSeparadoFamiliaLoja = 0;
decimal _estoqueTransitoFamiliaLoja = 0;
decimal _estoqueEntrarFamiliaLoja = 0;
decimal _estoqueLogicoFamiliaLoja = 0;
decimal _estoquePrevistoFamiliaLoja = 0;
DateTime dataInicialPeriodoVendas = DateTime.Now.AddDays(-30);
DateTime dataFinalPeriodoVendas = DateTime.Now;
_familiaProdutoAplicacao = new FamiliaProdutoAplicacao(_parametrosTask.repositorioEscopo);
_filialAplicacao = new FilialAplicacao(_parametrosTask.repositorioEscopo);
_dadosFamiliaFilialAplicacao = new DadosFamiliaFilialAplicacao(_parametrosTask.repositorioEscopo);
_giroObjetivoFamiliaProdutoAplicacao = new GiroObjetivoFamiliaProdutoAplicacao(_parametrosTask.repositorioEscopo);
_saldoEstoqueProdutoAplicacao = new SaldoEstoqueProdutoAplicacao(_parametrosTask.repositorioEscopo);
_resumoVendasAplicacao = new ResumoVendasAplicacao(_parametrosTask.repositorioEscopo);
_legendaLinhaAplicacao = new LegendaLinhaAplicacao(_parametrosTask.repositorioEscopo);
_wrkGenerico01Aplicacao = new WrkGenerico01Aplicacao(_parametrosTask.repositorioEscopo);
_parametroClasseABCFamiliaAplicacao = new ParametroClasseABCFamiliaAplicacao(_parametrosTask.repositorioEscopo);
_usuarioAtualAplicacao = new UsuarioAplicacao(_parametrosTask.repositorioEscopo);
Int64 _idPrimeiroNivelFamilia = _familiaProdutoAplicacao.RepositorioFamiliaProduto.ObterPorCodigo(_parametrosTask.familia.Codigo.Split('.')[0]).FirstOrDefault().Id;
ParametroClasseABCFamilia _parametroClasseABCFamilia = _parametroClasseABCFamiliaAplicacao.ParametroClasseABCFamiliaPorFamiliaClasse(_parametrosTask.filialSelecionada.Id, _idPrimeiroNivelFamilia).FirstOrDefault();
ClasseGenericaFamiliaProduto _classeGenericaFamiliaProduto = new ClasseGenericaFamiliaProduto();
_saldoEstoqueProdutoAplicacao.ObterSaldoEstoqueProdutosFamilia(_usuarioAtual.TipoEstoque.Id, _parametrosTask.filialSelecionada, _parametrosTask.familia.Codigo, true, out _estoqueLogicoFamiliaLoja, false, out _estoqueSeparadoFamiliaLoja, false, out _estoqueTransitoFamiliaLoja, false, out _estoqueEntrarFamiliaLoja, true, out _estoquePrevistoFamiliaLoja);
_classeGenericaFamiliaProduto.Filial = _parametrosTask.filialSelecionada.Codigo + " - " + _parametrosTask.filialSelecionada.Apelido;
try { _classeGenericaFamiliaProduto.LinhaProduto = _parametrosTask.familia.FamiliaMarcadaCapacidadeGondola.LegendaLinha.Descricao; }
catch (Exception) { _classeGenericaFamiliaProduto.LinhaProduto = ""; };
_classeGenericaFamiliaProduto.Familia = _parametrosTask.familia.Codigo;
_classeGenericaFamiliaProduto.DescricaoFamilia = _parametrosTask.familia.Nome;
try { _classeGenericaFamiliaProduto.Vendas30Dias = Arredondar((decimal)_resumoVendasAplicacao.RepositorioResumoVendas.ObterQuantidadeVendaPorFamiliaFilial(_parametrosTask.filialSelecionada.Id, _parametrosTask.familia.Id, dataInicialPeriodoVendas, dataFinalPeriodoVendas)); }
catch (Exception) { Arredondar(_classeGenericaFamiliaProduto.Vendas30Dias = 0); };
_totalVendas30Dias += Arredondar(_classeGenericaFamiliaProduto.Vendas30Dias);
_classeGenericaFamiliaProduto.EstoqueAtual = Arredondar(_estoqueLogicoFamiliaLoja);
_totalEstoqueAtual += Arredondar(_classeGenericaFamiliaProduto.EstoqueAtual);
_classeGenericaFamiliaProduto.EstoquePrevisto = Arredondar(_estoquePrevistoFamiliaLoja);
_totalEstoquePrevisto += Arredondar(_classeGenericaFamiliaProduto.EstoquePrevisto);
_classeGenericaFamiliaProduto.CapacidadeMin = Arredondar(_dadosFamiliaFilialAplicacao.RepositorioDadosFamiliaFilial.ObterLimiteMaximoFamiliaEstoque(_familiaProdutoAplicacao.RepositorioFamiliaProduto, _usuarioAtual.LocalEstoqueAtual.Filial.Empresa.Id, _usuarioAtual.TipoEstoque.Id, _parametrosTask.familia.FamiliaMarcadaCapacidadeGondola.Codigo, _parametrosTask.familia.Codigo, _parametrosTask.filialSelecionada.Id).Select(d => d.Quantidade).FirstOrDefault());
_totalCapacidadeMin += Arredondar(_classeGenericaFamiliaProduto.CapacidadeMin);
try { _classeGenericaFamiliaProduto.CapacidadeMax = Arredondar(_familiaProdutoAplicacao.CalculoEstoqueMaximoFamilia(_classeGenericaFamiliaProduto.CapacidadeMin, _classeGenericaFamiliaProduto.Vendas30Dias, _parametrosTask.filialSelecionada.TempoReposicaoEmDias, _parametroClasseABCFamilia.FatorClasseFamilia, _parametroClasseABCFamilia.PercentualCabideFamilia)); }
catch (Exception) { Arredondar(_classeGenericaFamiliaProduto.CapacidadeMax = 0); };
_totalCapacidadeMax += Arredondar(_classeGenericaFamiliaProduto.CapacidadeMax);
try { _classeGenericaFamiliaProduto.GiroAtual = Arredondar((_classeGenericaFamiliaProduto.EstoqueAtual / _classeGenericaFamiliaProduto.Vendas30Dias) * 30); }
catch (Exception) { Arredondar(_classeGenericaFamiliaProduto.GiroAtual = 0); };
try { _classeGenericaFamiliaProduto.GiroPrevisto = Arredondar((_classeGenericaFamiliaProduto.EstoquePrevisto / _classeGenericaFamiliaProduto.Vendas30Dias) * 30); }
catch (Exception) { Arredondar(_classeGenericaFamiliaProduto.GiroPrevisto = 0); };
try { _classeGenericaFamiliaProduto.GiroCapacidadeMax = Arredondar((_classeGenericaFamiliaProduto.CapacidadeMax / _classeGenericaFamiliaProduto.Vendas30Dias) * 30); }
catch (Exception) { Arredondar(_classeGenericaFamiliaProduto.GiroCapacidadeMax = 0); };
_classeGenericaFamiliaProduto.GiroObjetivo = Arredondar(_giroObjetivoFamiliaProdutoAplicacao.BuscaGiroObjetivoFamiliaMaisProxima(_parametrosTask.familia.Codigo, _parametrosTask.filialSelecionada.Id));
_totalGiroObj += Arredondar(_classeGenericaFamiliaProduto.GiroObjetivo);
try { _classeGenericaFamiliaProduto.GiroIdeal = Arredondar((_classeGenericaFamiliaProduto.Vendas30Dias / 30) * _classeGenericaFamiliaProduto.GiroObjetivo); }
catch (Exception) { Arredondar(_classeGenericaFamiliaProduto.GiroIdeal = 0); };
_classeGenericaFamiliaProduto.NecessidadeGiro = (Arredondar(_classeGenericaFamiliaProduto.GiroIdeal - _classeGenericaFamiliaProduto.EstoquePrevisto) < 0 ? 0 : Arredondar(_classeGenericaFamiliaProduto.GiroIdeal - _classeGenericaFamiliaProduto.EstoquePrevisto));
_classeGenericaFamiliaProduto.NecessidadeCapacidade = (Arredondar(_classeGenericaFamiliaProduto.CapacidadeMax - _classeGenericaFamiliaProduto.EstoquePrevisto) < 0 ? 0 : Arredondar(_classeGenericaFamiliaProduto.CapacidadeMax - _classeGenericaFamiliaProduto.EstoquePrevisto));
try { _classeGenericaFamiliaProduto.SGiro = Formatar((_classeGenericaFamiliaProduto.GiroPrevisto / _classeGenericaFamiliaProduto.GiroObjetivo) * 100); }
catch (Exception) { Formatar(_classeGenericaFamiliaProduto.SGiro = 0); };
_listaClasseGenericaFamiliaProduto.Add(_classeGenericaFamiliaProduto);
}
Have you been able to identify which appointments are lengthy? My bet: a change in just one or two lines can improve several times the response time of this part of your system. I’d start by analyzing this one:
_familiaProdutoAplicacao.RepositorioFamiliaProduto.Todos().Where(...
- see that you first return more records than you need and then make a selection in memory. Although its design does not seem ideal, most of the time the performance problem is localized. Identify which of the queries is taking 80% of the time and come back here for us to take a look.– Caffé
Okay, thanks for the tip! makes sense! I will implement. However my doubt is another.
– Vinicius Botelho Bizarri
Hmm your question is with threads, right? I ended up focusing on what seemed to be the real problem and forgot about threads. Your design opens up a lot of holes for problems when working with threads. Since you’re open to suggestions, my suggestion is: don’t use threads. They are not designed to solve performance problems, let alone performance problems in queries to Dbms (they themselves open threads when necessary). It’s best to go back to the previous code without threads, identify and solve performance issues.
– Caffé
Well, with your tips and a lot of reading I ended up abandoning this idea of threads doing several parallel accesses to the comic book and chose to change the structure a little and improve my queries. Thank you.
– Vinicius Botelho Bizarri