Compartilhar via


Dicas para melhorar o código de time crítico

Escrever código rápido exige noções básicas sobre todos os aspectos do seu aplicativo e como ele interage com o sistema.Este tópico sugere alternativas para algumas das técnicas de codificação mais óbvias para ajudar a garantir que as partes críticas de time do seu código executem satisfatoriamente.

Para resumir, melhorar o código de time crítico exige que você:

  • Sabe quais partes do seu programa precisam ser rápido.

  • Sabe o dimensionar e velocidade do seu código.

  • Sabe o custo de novos recursos.

  • Sabe o trabalho mínimo necessário para realizar o trabalho.

Para obter informações sobre o desempenho do seu código, você pode usar o monitor de desempenho (perfmon.exe).

  • Acertos de cache e falhas de página

  • Classificação e pesquisa

  • MFC e bibliotecas de classes

  • Bibliotecas compartilhadas

  • Pilhas

  • Segmentos (Threads)

  • Conjunto de trabalho pequeno

Erros de cache e falhas de página

Perdeu acertos do cache, em ambos sistema autônomo interno e externo cache, bem sistema autônomo falhas de página (Ir para o armazenamento secundário para dados e instruções de programa) degradar o desempenho de um programa.

Um acerto de cache da CPU pode custar ciclos de clock de 10 a 20 seus programa.Um acerto de cache externo pode custar 20–40 ciclos de clock.Uma falha de página pode custar ciclos de relógio de um milhão (supondo que um processador que manipula 500 milhões de instruções por segundo e um time de 2 milissegundos para uma falha de página).Portanto, ele é o interesse de execução do programa para escrever código que reduzirá o número de acertos de cache perdidas e falhas de página.

Um motivo para programas lentos é que eles tenham mais falhas de página ou ignorado o cache com mais freqüência do que o necessário.Para evitar isso, é importante usar estruturas de dados com mercadoria localidade de referência, que significa manter itens relacionados juntos.Às vezes, uma estrutura de dados que parece ótima é horrible causa de mau localidade de referência e, às vezes, o inverso é verdadeiro.Aqui estão dois exemplos:

  • Alocada dinamicamente listas vinculadas podem reduzir o desempenho do programa porque quando você Pesquisar um item ou quando percorrer uma lista no participante, cada link ignorado pode perder o cache ou causar uma falha de página.Uma implementação de lista com base em matrizes simples, na verdade, pode ser muito mais rápida por causa do cache do melhor e menos falhas de página ainda — permitindo a fato que a matriz seria mais difícil de crescer, ainda pode ser mais rápido.

  • Tabelas de hash que usam alocadas dinamicamente listas vinculadas podem prejudicar o desempenho.Por extensão, tabelas de hash usado por listas vinculadas dinamicamente alocadas para armazenar seu Sumário podem realizar consideravelmente pior.Na verdade, na análise final, uma Pesquisar linear simples por meio de uma matriz, na verdade, talvez mais rápida (dependendo das circunstâncias).Tabelas de hash com base em array (chamados "fechada hash") é uma implementação de muitas vezes negligenciado que tem um desempenho superior com freqüência.

Classificação e pesquisa

A classificação é inerentemente demorada em comparação com várias operações típicas.A melhor maneira de evitar a diminuição desnecessária é evitar a classificação em momentos importantes.Talvez você possa:

  • Adiar a classificação até que um não-desempenho–critical time.

  • Classificar os dados em uma versão anterior, não-desempenho–critical time.

  • Classificar somente a parte dos dados que realmente precisam de classificação.

Às vezes, você pode criar a lista em ordem classificada.Tenha cuidado, porque se você precisar inserir dados em ordem classificada, talvez seja necessária uma estrutura de dados mais complicada com má localidade de referência, entrelinhamento a erros de cache e falhas de página.Não há nenhuma abordagem funciona em todos os casos.Experimente várias abordagens e medir as diferenças.

Aqui estão algumas dicas Geral para classificação:

  • Use uma classificar das ações para minimizar erros.

  • Qualquer trabalho que você pode fazer com antecedência para reduzir a complexidade da classificar vale a pena.Se uma única passagem sobre os seus dados simplifica as comparações e reduz a classificar de O (n log n) to O(n), você irá certamente surgem ahead*.*

  • Pense sobre a localidade de referência o algoritmo de classificar e os dados que você esperava que ele seja executado em.

Há menos alternativas para pesquisas de classificação.Se a Pesquisar for time crítica um binário Pesquisar de tabela de Pesquisar ou hash quase sempre é melhor, mas sistema autônomo ocorre com a classificação, você deve ter a localidade em mente.Uma Pesquisar linear através de uma matriz pequena pode ser mais rápido do que uma Pesquisar binária através de uma estrutura de dados com muitos dos ponteiros que causa falhas de página ou erros de cache.

MFC e bibliotecas de classes

Microsoft Foundation Classes (MFC) pode simplificar bastante a escrever código.Ao escrever código de time crítico, você deve estar ciente da sobrecarga inerente em algumas das classes.Examine o código do MFC pelo seu código de time crítico para ver se ele atende às suas necessidades de desempenho.A lista a seguir identifica classes MFC e funções que você deve conhecer:

  • CString   MFC chama o C em time de execução biblioteca para alocar memória para um CString dinamicamente.Falando em geral, CString é tão eficiente quanto qualquer Outros seqüência alocados dinamicamente. sistema autônomo com qualquer seqüência alocada dinamicamente, ele tem a sobrecarga de alocação dinâmica e versão.Freqüentemente, um simples char matriz na pilha pode servir o mesmo objetivo e é mais rápida. Não use um CString armazene uma seqüência de caracteres constante. Use Const char * em vez disso.Qualquer operação que você executar com um CString o objeto tem uma sobrecarga. Usando a biblioteca de time de execução funções de cadeia de caracteres pode ser mais rápido.

  • CArray   UM CArray fornece flexibilidade que não uma matriz normal, mas o programa talvez não precise que.Se você souber os limites específicos para o array, você pode usar uma matriz global fixa.Se você usar CArray, use CArray::SetSize para estabelecer seu dimensionar e especifique o número de elementos que aumenta quando for necessária uma realocação.Caso contrário, adicionando elementos pode fazer com que o array com freqüência sejam realocados e copiados, que é ineficiente e pode fragmentar memória.Esteja ciente também de que se você insere um item em uma matriz, CArray move os itens subseqüentes na memória e pode ser necessário aumentar a matriz.Essas ações podem causar erros de cache e falhas de página.Se você olhar o código que use MFC, você pode ver que você pode escrever algo mais específico para seu cenário para melhorar o desempenho.Desde CArray é um modelo, por exemplo, você poderá fornecer CArray especializações em tipos específicos.

  • CList   CList é um duplamente lista vinculada, portanto, a inserção de elemento é rápida no topo, final e em uma posição conhecida (POSIÇÃO) na lista.Pesquisar um elemento por valor ou índice requer uma pesquisa sequencial, no entanto, que pode seja lenta se a lista é longa.Se seu código não precisar de uma lista duplamente vinculada convém reconsiderar usando CList. Usando uma lista vinculada separada salva a sobrecarga de atualização de um ponteiro para todas sistema autônomo operações adicional, bem sistema autônomo a memória desse ponteiro.A memória adicional não é bom, mas é outra oportunidade para erros de cache ou falhas de página.

  • IsKindOf   Esta função pode gerar número de chamadas e acessar muita memória em áreas de dados diferentes, entrelinhamento a localidade incorreta de referência. É útil para uma compilação de depurar (em uma telefonar de declaração, por exemplo), mas evite usá-lo em uma versão de compilação.

  • PreTranslateMessage   Uso PreTranslateMessage Quando uma árvore específica do windows precisa aceleradores de teclado diferentes ou quando é necessário inserir a manipulação de mensagens na bomba de mensagem. PreTranslateMessage Altera as mensagens de despacho do MFC. Se você substituir PreTranslateMessage, para que somente no nível do necessário. Por exemplo, não é necessário substituir CMainFrame::PreTranslateMessage se você estiver interessado somente em mensagens vai filhos de um determinado modo de exibição.Substituir PreTranslateMessage para o modo de exibição de classe em vez disso.

    Não ignorar o caminho de despacho normal usando PreTranslateMessage para tratar qualquer mensagem enviada para qualquer janela. Use procedimentos de janela e MFC mensagem mapas para essa finalidade.

  • OnIdle   Ocioso de eventos pode ocorrer em horários que você não espera, tal sistema autônomo entre WM_KEYDOWN e WM_KEYUP eventos.Timers podem ser uma maneira mais eficiente para acionar o seu código.Não force OnIdle para ser chamado repetidamente gerando mensagens falsas ou retornando sempre TRUE de uma substituir de OnIdle, que nunca permitiria que o thread em suspensão. Novamente, um cronômetro ou um thread separado pode ser mais apropriado.

Bibliotecas compartilhadas

Reutilização de código é desejável.No entanto, se você for usar o código de outra pessoa, verifique se que você sabe exatamente o que ele faz nesses casos onde o desempenho é fundamental para você.A melhor maneira de entender isso está passando pelo código de fonte ou medir com ferramentas sistema autônomo PView ou o Monitor de desempenho.

Pilhas

Use várias pilhas com discrição.Pilhas adicionais criadas com HeapCreate and HeapAlloc permitem que você gerencie e, em seguida, descarte de um conjunto relacionado de alocações.Não confirme muita memória.Se você estiver usando várias pilhas, preste especial atenção à quantidade de memória que está inicialmente comprometida.

Em vez de várias pilhas, você pode usar auxiliar funções para fazer a interface entre o código e heap padrão.Funções auxiliares facilitam a estratégias de alocação personalizada que podem melhorar o desempenho do seu aplicativo.Por exemplo, se você executar pequenas alocações com freqüência, convém localizar essas alocações de uma parte da heap padrão.Você pode alocar um bloco grande de memória e use uma função auxiliar para subalocar desse bloco.Se você fizer isso, você não tenha pilhas adicionais com a memória não utilizada porque a alocação está saindo de heap padrão.

Em alguns casos, no entanto, usando o padrão heap pode reduzir a localidade de referência.Use Visualizar processos, Spy ++ ou desempenho do sistema para medir os efeitos da movimentação de objetos de heap para heap.

Meça as pilhas para que você pode considerar cada alocação de na pilha.Usar o time de execução C Depurar rotinas de heap para o ponto de verificação e a pilha do despejo.Você pode ler a saída em um programa de planilha eletrônica como o Microsoft Excel e usar tabelas dinâmicas para exibir os resultados.Anote o número total, dimensionar e distribuição de alocações.comparar isso com o dimensionar dos conjuntos de trabalho.Observe também o clustering de objetos relacionados ao tamanho.

Você também pode usar os contadores de desempenho para monitorar o uso de memória.

Segmentos (Threads)

Para plano de fundo tarefas, tratamento ocioso efetivo de eventos de pode ser mais rápido que usando segmentos.É mais fácil entender a localidade de referência em um programa de thread único.

Uma mercadoria regra prática é usar um thread somente se uma notificação do sistema operacional que você bloco em está na raiz do trabalho em segundo plano.Segmentos são a melhor solução nesse caso porque ele é impraticável para bloquear um segmento principal em um evento.

Threads também apresentam problemas de comunicação.Você deve gerenciar o link de comunicação entre os segmentos, com uma lista de mensagens ou alocando e uso de memória compartilhada.Gerenciar o link de comunicação geralmente requer sincronização para evitar condições de corrida e deadlock problemas.Essa complexidade pode transformar com com facilidade em erros e problemas de desempenho.

Para obter informações adicionais, consulte Processamento de loop ocioso and Multithreading.

Conjunto de trabalho pequeno

Conjuntos de trabalho menores significam melhor localidade de referência, menos falhas de página e mais acertos do cache.O conjunto de trabalho do processo é a métrica mais próxima que o sistema operacional fornece diretamente para medir a localidade de referência.

  • Para definir os limites superiores e inferiores do conjunto de trabalho, use SetProcessWorkingSetSize.

  • Para obter os limites superiores e inferiores do conjunto de trabalho, use GetProcessWorkingSetSize.

  • Para exibir o dimensionar do conjunto de trabalho, use o Spy ++.

Consulte também

Referência

Otimizando seu código