Padrões comuns para aplicativos multithread de mau comportamento
O Visualizador de Concorrência permite aos desenvolvedores visualizar o comportamento de um aplicativo de várias threads.Essa ferramenta inclui uma galeria de padrões comuns para aplicativos de várias threads mal comportados.A galeria inclui padrões visuais típicos e reconhecíveis que são expostas pela ferramenta, juntamente com uma explicação do comportamento representado por cada padrão, o resultado provável desse comportamento, e a abordagem mais comum para resolvê-lo.
Contenção de Bloqueios e Execução em Série
Algumas vezes um aplicativo com execução paralela teimosamente continua a executar em série mesmo tendo várias threads e o computador tendo uma quantidade suficiente de núcleos lógicos.O primeiro é sintoma é o desempenho ruim para execução com várias threads, talvez até mesmo um pouco mais lento do que uma implementação serial.Na Exibição de Threads, não se vê várias threads executando paralelamente; em vez de isso, se vê apenas um segmento em execução a qualquer momento.Neste ponto, se você clicar em um segmento de sincronização de uma thread, você poderá ver uma pilha de chamadas para a thread bloqueada (a pilha da chamada de bloqueio) e a thread que removeu a condição de bloqueio (pilha da chamada de desbloqueio).Além disso, se a pilha da chamada de desbloqueio ocorrer no processo que você estiver analisando, um conector Thread-Ready será exibido.A partir deste ponto, você pode navegar para seu código a partir das pilhas das chamadas de bloqueio e desbloqueio para investigar ainda mais a causa da serialização.
Conforme mostrado no exemplo a seguir, o Visualizador de Concorrência também pode expor este sintoma na Visualização de Utilização da CPU, onde, independentemente da presença de várias threads, o aplicativo principal consome apenas um núcleo lógico.
1 Padrão de desempenho Para obter mais informações, consulte “: Identificando a contenção de bloqueio no blog de Hazim Shafi Ferramentas de desempenho do windows paralelas no site do blog do MSDN.
Distribuição de Trabalho Desigual
Quando a distribuição de trabalho entre várias threads paralelas de um aplicativo é irregular, um padrão típico de escada surge à medida que cada thread termina seu trabalho, conforme mostrado na ilustração anterior. O Visualizador de Concorrência frequentemente mostra tempos de início muito próximos para cada thread concorrente.Entretanto, estas threads tipicamente terminam de forma irregular em vez de terminar simultaneamente.Esse padrão indica uma distribuição de trabalho irregular em um grupo de threads paralelas, o que pode levar a um desempenho diminuído.A melhor abordagem para esse problema é reavaliar o algoritmo que divide o trabalho em threads paralelas.
Conforme mostrado na ilustração a seguir, o Visualizador de Concorrência também pode mostrar este sintoma na Visualização de Uso da CPU como um decréscimo gradual na utilização da CPU.
Sobrecarga
Em caso de sobrecarga, o número de threads ativas em um processo é maior que o número de núcleos lógicos disponíveis no sistema.A ilustração anterior mostra os resultados de uma sobrecarga, com faixas de preterição significativas em todos as threads ativos.Além disso, a legenda mostra que uma grande porcentagem de tempo é gasta em Preterição (84 por cento nesse exemplo).Isto pode indicar que o processo está solicitando que o sistema execute mais threads concorrentes que o número de núcleos lógicos.No entanto, isso também pode indicar que outros processos no sistema estão usando recursos que foram supostos disponíveis para esse processo.
Você deve considerar o seguinte quando ao avaliar esse problema:
O sistema global pode estar sobrecarregado.Considere que outros processos no sistema podem estar preterindo suas threads.Ao passar sobre um segmento de preterição na visualização de threads, uma dica de ferramenta identificará o segmento e o processo que preteriu a thread.Este processo não é necessariamente o que foi executado durante o tempo todo em o seu processo que foi preterido, mas fornece uma dica sobre o que criou a pressão de preterição no seu processo.
Avalie como seu processo determina o número apropriado de threads para a execução durante essa fase de trabalho.Se seu processo calcula diretamente o número de threads paralelas ativos, considere alterar esse algoritmo para considerar melhor o número de núcleos lógicos disponíveis no sistema.Se você usar o Runtime de Concorrência, a Biblioteca Paralela de Tarefas, ou PLINQ, essas bibliotecas executam o trabalho de calcular o número de threads.
E/S ineficiente
O uso exagerado ou indevido de E/S são uma causa comum de ineficiências em aplicativos.Considere a ilustração anterior.O Perfil Visível de Linha do Tempo mostra que 42 por cento do tempo visível de thread é consumido por E/S.A linha do tempo mostra grandes quantidades de E/S, o que indica que o aplicativo analisado é freqüentemente bloqueado por E/S.Para obter detalhes sobre os tipos de E/S e onde seu programa é bloqueado, dê zoom em regiões problemáticas, examine o Perfil Visível da Linha do Tempo, e clique em um bloco específico de E/S para ver as pilhas de chamadas atuais.
Comboios de Bloqueios
Comboios de bloqueios ocorrem quando o aplicativo obtém bloqueios em uma ordenação primeiro a chegar, primeiro a sair, e quando a taxa de chegada no bloqueio é maior do que a taxa de aquisição.A combinação dessas duas condições faz que que solicitações para o bloqueio sejam colocadas em espera.Uma maneira de combater esse problema é usar bloqueios “injustos”, ou bloqueios que forneçam acesso à primeira thread para localizá-las em estados desbloqueados.A ilustração anterior mostra esse comportamento de comboio.Para resolver o problema, tente reduzir a disputa entre objetos de sincronização e tente usar bloqueios injustos.