Como limitar os recursos usados pelo sistema? – c# .net winforms
Pergunta:
Tenho um laço de repetição que faz várias iterações e possui em seu escopo cálculos que exigem muito processamento.
O problema é que ao executar o trecho do código, o uso do processador se elevar gradativamente, até travar a aplicação e posteriormente o sistema operacional.
Bem, meu objetivo é limitar de alguma forma o consumo desses recursos que levam ao travamento do sistema. Sei que isso aumentará o tempo de resposta, mas minha prioridade no momento é não travar o sistema.
O projeto está em Windows Forms, mas este trecho está em uma
Class Library.
Veja um trecho do código:
private static string[] TodosPossiveis(char[,] letras)
{
int linhas = letras.GetUpperBound(1) + 1;
int colunas = letras.GetUpperBound(0) + 1;
int max = (int)Math.Pow(linhas, colunas);
string[] todos = new string[max];
int[] posY = new int[colunas];
int atual = 0;
while (atual < max)
{
string nova = "";
for (int i = 0; i < colunas; i++)
{
nova += letras[i, posY[i]];
}
for (int i = colunas - 1; i > -1; i--)
{
posY[i]++;
if (posY[i] == linhas)
{
posY[i] = 0;
}
else
{
break;
}
}
todos[atual++] = nova;
}
return todos;
}
Este método recebe um conjunto de caracteres e devolve todas as combinações possíveis.
Tentei usar apenas variáveis primitivas para melhorar no desempenho, mas mesmo assim, ao receber um conjunto grande de caracteres o sistema acaba travando.
Autor da pergunta Jedaias Rodrigues
Maniero
A primeira tarefa que deve fazer é pensar se tem uma forma melhor de executar isto. Eu duvido que precise de uma algoritmo tão pesado. Ou ele não é tão pesado assim. Sem um contexto completo não dá para ajudar. E nem é o foco da pergunta.
Avalie se não está tendo problema de memória. Sem saber exatamente onde está o problema, vai achar a solução errada.
Vou repetir, a solução real é perfilar e achar um algoritmo, e talvez estrutura de dados, melhores.
Se não consegue melhorá-lo e realmente esteja atrapalhando, então o sistema operacional é que deve ser responsável por dar mais ou menos prioridade ao processo.
Dá para fazer isto chamando o programa com start ou mandar seu próprio código diminuir prioridade com a propriedade Process.PriorityClass. Um BelowNormal deve servir, ou pode exagerar e colocar em Idle.
A propriedade Process.ProcessorAffinity pode ajudar evitando que todos os cores sejam usados pelo processo.
Existe a possibilidade de criar algum código que minimize isto, mas não acho um boa solução na maioria dos casos. É gambiarra maior ainda.
Cuidado para não fazer gambiarras que parecem resolver e só pioram.
Usando esse tutorial você vai conseguir separar esse processamento. Vai consumir o recurso da maquina, mas não vai travar a maquina, ainda via poder calcular percentual, contar o processamento, etc atualizando na tela.
Veja esse Link
Tendo algum problema no seu código é só dizer, podemos fazer o acompanhamento em outra pergunta se for o caso.
Espero ter ajudado
Eu trabalhei em um sistema de Orçamento de Recursos Humanos que processava o orçamento da folha de pagamento de mais de 500 mil funcionários, com várias etapas de cálculo que realmente consumiam muito os recursos do sistema operacional.
A solução que encontraram foi deixar uma máquina dedicada para o cálculo, e a chamaram convenientemente de “Máquina de Cálculo”. Dessa forma, o sistema ficava separado do processamento do cálculo, e permitia que o usuário solicitasse a execução do cálculo para pegar os resultados depois que já estivessem prontos.
Talvez isso funcione para você também. Então, em vez de tentar processar tudo de uma vez e já mostrar os resultados para o usuário, basta você notificar o usuário que o processamento foi iniciado e está em andamento, e depois que o processamento for concluído você notifica ao usuário e apresenta os resultados a ele. Isso pode ser tanto em arquivo, relatório ou em uma tela de seu sistema.
Eu sei que é um post antigo, mas ainda assim tem alguns pontos que valem ser listados…
1) A carga de memória pesada e lentidão não surpreendem, uma vez que vc está tentando alocar todas as possibilidades em memória ANTES de retornar. Se vc passar um array de input de 10×10, a variável max será 1E10, ou 1 com 10 zeros na frente. Pense que se vc tentar alocar um array de retorno deste tamanho, ele terá no mínimo essa quantidade de consumo de bytes, o que dá uns 9,3 GIGAS de memória para alocar isso tudo… fora o tamanho de cada palavra em si…
Um jeito de contornar isso é usar o operador yield return. Veja estes links:
- Qual a utilidade da palavra reservada “yield”?
- https://www.dotnetperls.com/yield
- https://docs.microsoft.com/pt-br/dotnet/csharp/language-reference/keywords/yield
Com isso, vc evita alocar tudo em memória. Outro ponto é mudar o retorno para IEnumerable<string>.
2) No trecho nova += letras[i, posY[i]];, ao invés de usar o operador += use um objeto StringBuilder – veja exemplos aqui.
A cada iteração nesta linha, o .NET é obrigado a realocar memória para construir a string atual.



