Muitas postagens analisaram o mecanismo Try-Catch e seu impacto no desempenho.
Entretanto, não há evidências de que o Try-Catch consuma muito desempenho do sistema, especialmente em um ambiente hospedado. Lembro-me que um internauta no jardim usou o StopWatch para analisar os indicadores de tempo de execução do código Try-Catch em diferentes circunstâncias em comparação com o código sem Try-Catch, e os resultados não foram muito diferentes.
Deixe-me analisar o Try-Catch em combinação com o IL.
● Análise do mecanismo
O mecanismo básico de captura e tratamento de exceções em .Net é completado pelos blocos try...catch...finally, que completam respectivamente o monitoramento, captura e processamento de exceções. Um bloco try pode corresponder a zero ou mais blocos catch e pode corresponder a zero ou um bloco finalmente. No entanto, uma tentativa sem captura parece sem sentido. Se a tentativa corresponder a múltiplas capturas, depois de detectar uma exceção, o CLR pesquisará o código do bloco catch de cima para baixo e filtrará a exceção correspondente através do filtro de exceção. Se for não for encontrado, então o CLR procurará exceções correspondentes ao longo da pilha de chamadas para níveis mais altos. Se a exceção correspondente ainda não for encontrada no topo da pilha, uma exceção não tratada será lançada. Neste momento, o código no O bloco catch não será executado. Portanto, o bloco catch mais próximo de try será percorrido primeiro.
Se houver o seguinte código:
try
{
Convert.ToInt32("Try");
}
catch (FormatException ex1)
{
string CatchFormatException = "CatchFormatException";
}
catch (NullReferenceException ex2)
{
string CatchNullReferenceException = "CatchNullReferenceException";
}
finally
{
string Finally = "Finally";
}
O IL correspondente é o seguinte:
.method private hidebysig instance void Form1_Load(object sender,
class [mscorlib]System.EventArgs e) cil managed
{
// Code size 53 (0x35)
.maxstack 1
.locals init ([0] class [mscorlib]System.FormatException ex1,
[1] string CatchFormatException,
[2] class [mscorlib]System.NullReferenceException ex2,
[3] string CatchNullReferenceException,
[4] string Finally)
IL_0000: nop
IL_0001: nop
IL_0002: ldstr "Try"
IL_0007: call int32 [mscorlib]System.Convert::ToInt32(string)
IL_000c: pop
IL_000d: nop
IL_000e: leave.s IL_0026
IL_0010: stloc.0
IL_0011: nop
IL_0012: ldstr "CatchFormatException"
IL_0017: stloc.1
IL_0018: nop
IL_0019: leave.s IL_0026
IL_001b: stloc.2
IL_001c: nop
IL_001d: ldstr "CatchNullReferenceException"
IL_0022: stloc.3
IL_0023: nop
IL_0024: leave.s IL_0026
IL_0026: nop
IL_0027: leave.s IL_0033
IL_0029: nop
IL_002a: ldstr "Finally"
IL_002f: stloc.s Finally
IL_0031: nop
IL_0032: endfinally
IL_0033: nop
IL_0034: ret
IL_0035:
// Exception count 3
.try IL_0001 to IL_0010 catch [mscorlib]System.FormatException handler IL_0010 to IL_001b
.try IL_0001 to IL_0010 catch [mscorlib]System.NullReferenceException handler IL_001b to IL_0026
.try IL_0001 to IL_0029 finally handler IL_0029 to IL_0033
} // end of method Form1::Form1_Load
As últimas linhas de código revelam como o IL lida com o tratamento de exceções. Cada item nas últimas três linhas é chamado de cláusula de tratamento de exceção, o EHC forma a tabela de tratamento de exceção e o EHT é separado do código normal pela instrução ret return.
Pode-se ver que FormatException está classificado em primeiro lugar no EHT.
Quando o código é executado com sucesso ou retorna vice-versa, o CLR atravessa o EHT:
1. Se uma exceção for lançada, o CLR encontrará o EHC correspondente de acordo com o "endereço" do código que lança a exceção (IL_0001 a IL_0010 é o intervalo do código de detecção). Neste exemplo, o CLR encontrará 2 EHCs e FormatException serão percorridos primeiro e é um EHC adequado.
2. Se o endereço do código retornado estiver entre IL_0001 a IL_0029, o manipulador final, ou seja, o código de IL_0029 a IL_0033 também será executado, independentemente de ser retornado devido à execução bem-sucedida do código.
Na verdade, o trabalho de travessia de catch e finalmente é executado separadamente. Como mencionado acima, a primeira coisa que o CLR faz é percorrer o bloco catch. Quando o bloco catch apropriado é encontrado, ele então percorre o bloco correspondente finalmente; e este processo será executado recursivamente por pelo menos duas vezes, porque o compilador traduz o try...catch...finally do C# em dois níveis de aninhamento em IL.
Obviamente, se o bloco catch correspondente não for encontrado, o CLR será executado finalmente e imediatamente interromperá todos os threads. O código no bloco Finalmente será definitivamente executado independentemente de try detectar uma exceção.
Sugestões para melhorar
Pode-se concluir do conteúdo acima:
Se "Try-Catch" for usado e uma exceção for capturada, tudo o que o CLR faz é percorrer os itens Catch na Tabela de Tratamento de Exceções; em seguida, ele percorre os itens Finalmente na Tabela de Tratamento de Exceções novamente, e quase todo o tempo é gasto percorrendo a Tabela de Tratamento de Exceções. e se nenhuma exceção for capturada, o CLR apenas percorre os itens Finalmente na Tabela de Tratamento de Exceções, e o tempo necessário é mínimo.
O tempo necessário para executar a operação correspondente após a travessia "Try-Catch" é determinado de acordo com seu código específico. "Try-Catch" causa apenas monitoramento e acionamento, e esta parte do tempo de código não deve ser contada como "Try- Pegar". consumo.
Portanto, podemos considerar tanto o desempenho quanto a revisão do código. Geralmente, as seguintes diretrizes são recomendadas:
1. Tente fornecer ao CLR informações claras sobre exceções e não use Exception para filtrar exceções.
2. Tente não escrever try...catch em um loop
3. Tente usar o mínimo de código possível. Se necessário, você pode usar vários blocos catch e escrever o tipo de exceção com maior probabilidade de ser lançado na posição mais próxima da tentativa.
4. Não declare apenas um objeto Exception sem manipulá-lo. Fazer isso aumenta o comprimento da Tabela de Tratamento de Exceções em vão.
5. Use as "Exceções CLR" do utilitário contador de desempenho para detectar exceções e otimizar adequadamente
6. Use o modo Try-Parse do membro. Se uma exceção for lançada, substitua-a por false.
Concluindo, embora o Try-Catch consuma um pouco de tempo, os programadores não precisam falar sobre isso. Pela análise acima, não é tanto que o "Try-Catch" perca ou afete o desempenho. É melhor dizer que "Try-Catch" é como outros códigos. Consumidores comuns de desempenho, mas para fins de revisão da escrita do código, tente prestar atenção em "Try-Catch".
Sinto-me como a análise do chefe, com o link original em anexo: https://m.xp.cn/b.php/75621.html