Qual é o custo da reflexão do .NET?

210

Eu constantemente ouço o quão ruim é a reflexão. Enquanto geralmente evito a reflexão e raramente encontro situações em que é impossível resolver meu problema sem ela, fiquei pensando ...

Para aqueles que usaram a reflexão em aplicativos, você mediu o desempenho e é realmente tão ruim?

Dan Herbert
fonte
Você também pode querer verificar esta pergunta. stackoverflow.com/questions/224232/…
smaclell
1
Use a API em FastFlect.codeplex.com. Isso acelerará a reflexão em 500x para getters / setters / invokers e outras coisas. A fonte e as informações sobre como ele funciona também estão disponíveis se você precisar estendê-lo.
Brandon Moore
3
Como essas informações saem em 2014? Alguma coisa mudou nesses 4 anos?
Arnthor 31/03
1
A tarefa simples de atribuir um valor a uma propriedade de instância é aproximadamente 150 vezes mais lenta, fazendo-o com reflexão (PropertyInfo.SetValue (instância, valor)) do que com codificação direta (instance.property = value) Isso está no .NET 4.0
Thanasis Ioannidis

Respostas:

130

Isto é. Mas isso depende do que você está tentando fazer.

Uso reflexão para carregar dinamicamente assemblies (plugins) e seu desempenho "penalidade" não é um problema, pois a operação é algo que faço durante a inicialização do aplicativo.

No entanto, se você estiver refletindo dentro de uma série de loops aninhados com chamadas de reflexão em cada um, eu diria que você deve revisitar seu código :)

Para operações "algumas vezes", a reflexão é perfeitamente aceitável e você não notará nenhum atraso ou problema com ela. É um mecanismo muito poderoso e é usado até pelo .NET. Por isso, não vejo por que você não deveria tentar.

Martin Marconcini
fonte
Eu tenho usado reflexão para obter método, nome da classe do método atual para registrar o erro no try-catch. basicamente para evitar codificar o nome da função ao registrar o erro. Eu preciso me preocupar?
Sangram Nandkhile
@Sangram não, isso é bom
Karthik AMR
@Sangram não, a menos que você está tendo um monte de erros que exigiam constantemente captura, que, em seguida, deve ser um problema diferente :)
Martin Marconcini
5
@ Sangram, enquanto o desempenho da reflexão não deve ser o problema no seu caso, parece que você está tentando
reimplementar as
152

Em sua palestra O desempenho das coisas cotidianas , Jeff Richter mostra que chamar um método pela reflexão é cerca de 1000 vezes mais lento do que chamá-lo normalmente.

Dica de Jeff: se você precisar chamar o método várias vezes, use a reflexão uma vez para encontrá-lo, atribua-o a um delegado e ligue para o delegado.

ESRogs
fonte
18
Também participei do Devscovery e concordo com esses resultados para o .NET 3.5. A recompilação do programa de benchmark de desempenho do Devscovery para .NET 4 mostra melhorias maciças! O custo cai para 100 vezes mais lento. Usando reflexão para typeof () pesquisas são inalterada entre .NET 3.5 e .NET 4.
John Wigger
61

O desempenho da reflexão dependerá da implementação (chamadas repetitivas devem ser armazenadas em cache, por exemplo:) entity.GetType().GetProperty("PropName"). Como a maior parte da reflexão que vejo diariamente é usada para preencher entidades de leitores de dados ou outras estruturas de tipo de repositório, decidi avaliar o desempenho especificamente na reflexão quando é usado para obter ou definir propriedades de objetos.

Eu criei um teste que considero justo, pois armazena em cache todas as chamadas repetidas e apenas vezes a chamada SetValue ou GetValue real. Todo o código-fonte para o teste de desempenho está em bitbucket em: https://bitbucket.org/grenade/accessortest . O escrutínio é bem-vindo e incentivado.

A conclusão a que cheguei é que não é prático e não fornece melhorias visíveis no desempenho para remover a reflexão em uma camada de acesso a dados que retorna menos de 100.000 linhas por vez quando a implementação da reflexão é bem-sucedida.

Gráfico de tempo (y) em relação ao número de entidades preenchidas (x)

O gráfico acima demonstra o resultado da minha pequena referência e mostra que os mecanismos que superam a reflexão só o fazem visivelmente após a marca de 100.000 ciclos. A maioria dos DALs retorna apenas várias centenas ou talvez milhares de linhas por vez e, nesses níveis, a reflexão funciona muito bem.

Grenade
fonte
9
Não necessariamente. Suas conversões de DAL podem ter apenas alguns milhares de itens, mas multiplique isso pelos usuários simultâneos que usam seu aplicativo (se for na Web) e isso poderá somar como se você convertesse milhões de itens. Se um método específico for 100 vezes mais lento, será muito mais lento em conjuntos pequenos e grandes. Mais lento é mais lento.
31812 Robert Koritnik
@RobertKoritnik Isso supondo que os métodos da web em seu servidor não são Asynchronous
Kurren
A assincronicidade @kurren não afeta a reflexão, mas os recursos do servidor. É claro que os métodos assíncronos da Web poderão atender a mais usuários, mas a reflexão ainda será lenta. E a reflexão por si só AFAIK é um processo síncrono de qualquer maneira. A busca de dados, por outro lado, será a única parte que funcionará bem no design assíncrono.
Robert Koritnik
3
Qual é o método Hyper no gráfico? Qual a diferença do Refletor?
Bryan Legend
Eu deveria ter mencionado isso @LoneCoder: codeproject.com/Articles/18450/... por stackoverflow.com/users/23354/marc-gravell
granada
14

Se você não estiver em um loop, não se preocupe.

David Plumpton
fonte
12

Minha experiência mais pertinente foi escrever código para comparar duas entidades de dados do mesmo tipo em um modelo de objeto grande em termos de propriedades. Entendi, tentei, corri como um cachorro, obviamente.

Fiquei desanimado e, durante a noite, percebi que, sem alterar a lógica, eu poderia usar o mesmo algoritmo para gerar automaticamente métodos para fazer a comparação, mas acessar estaticamente as propriedades. Não demorou muito tempo para adaptar o código para esse fim, e eu tive a capacidade de fazer uma comparação profunda de propriedades com entidades com código estático que podia ser atualizado com o clique de um botão sempre que o modelo de objeto era alterado.

O que quero dizer é: nas conversas com colegas, já que várias vezes indiquei que o uso da reflexão poderia ser para gerar automaticamente código para compilar, em vez de executar operações de tempo de execução, e isso geralmente vale a pena considerar.

Gaz
fonte
Considerando-se que Visual Studio tem um excelente suporte tal modelo, que é uma maneira prática de geração de código uso
Sebastian
12

Não massivamente. Eu nunca tive um problema com isso no desenvolvimento de desktop, a menos que, como Martin declara, você o esteja usando em um local tolo. Ouvi dizer que muitas pessoas têm medos totalmente irracionais sobre seu desempenho no desenvolvimento de desktops.

No Compact Framework (no qual geralmente estou), é praticamente um anátema e deve ser evitado como a praga na maioria dos casos. Ainda posso usá-lo com pouca frequência, mas tenho que ter muito cuidado com a aplicação, que é bem menos divertida. :(

Quibblesome
fonte
5
+1 por me ensinar uma nova palavra: anátema. Também para mencionar medos irracionais. Eu tenho medo de programadores que temem irracionalmente - isso mostra que eles realmente não sabem o que estão fazendo e apenas baseiam o que fazem no que as outras pessoas dizem a eles. tosse culto à carga tosse
bsneeze
1
Ahhhh Cargo Cult. Agora há um bom exemplo de comportamento humano curioso.
Quibblesome
10

É ruim o suficiente que você precise se preocupar até com a reflexão feita internamente pelas bibliotecas .NET para obter um código crítico de desempenho.

O exemplo a seguir é obsoleto - verdadeiro na época (2008), mas há muito tempo corrigido nas versões CLR mais recentes. A reflexão em geral ainda é uma coisa um pouco cara!

Caso em questão: você nunca deve usar um membro declarado como "Objeto" em uma instrução de bloqueio (C #) / SyncLock (VB.NET) no código de alto desempenho. Por quê? Como o CLR não pode bloquear um tipo de valor, o que significa que ele precisa fazer uma verificação do tipo de reflexão em tempo de execução para ver se o seu Objeto é realmente um tipo de valor em vez de um tipo de referência.

McKenzieG1
fonte
13
para ser justo, uma verificação do tipo de reflexão é rápida.
Jimmy Jimmy
1
Para esse 'código crítico de desempenho', você realmente deveria usar o .NET para começar?
Seph
1
@ Seph: Porções dinâmicas / de reflexão do .NET, no. Mas C # /. NET usual, por que não? As acelerações de C ++ vs C # são marginais na camada de aplicativo (o C ++ ainda é um pouco mais rápido em rotinas matemáticas intensivas). E eu estou supondo que você não está sugerindo montagem ...
DeepSpace101 31/01
Um tipo de valor em caixa (ou seja, objeto) pode ser bloqueado. @BryceWagner está correto.
Fowl #:
1
Para ser justo (para mim), é mais preciso dizer que a resposta é "obsoleta", em vez de "pura bobagem". Minhas observações sobre o comportamento de lock (obj) foram precisas no momento em que foram escritas, mas esse comportamento específico da implementação do CLR se foi há muito tempo.
McKenzieG1
5

Como em todas as coisas da programação, você precisa equilibrar o custo de desempenho com qualquer benefício obtido. A reflexão é uma ferramenta inestimável quando usada com cuidado. Criei uma biblioteca de mapeamento de O / R em C # que usava reflexão para fazer as ligações. Isso funcionou extraordinariamente bem. A maior parte do código de reflexão foi executada apenas uma vez; portanto, qualquer ocorrência de desempenho foi bastante pequena, mas os benefícios foram excelentes. Se eu estivesse escrevendo um novo algoritmo de classificação desordenado, provavelmente não usaria a reflexão, pois provavelmente teria uma escala ruim.

Compreendo que não respondi exatamente à sua pergunta aqui. O que quero dizer é que isso realmente não importa. Use a reflexão quando apropriado. É apenas mais um recurso do idioma que você precisa aprender como e quando usar.

Mike Thompson
fonte
3

A reflexão pode ter um impacto notável no desempenho se você a usar para criação de objetos frequentes. Desenvolvi aplicativos com base no Composite UI Application Block, que depende muito da reflexão. Houve uma degradação perceptível no desempenho relacionada à criação de objetos via reflexão.

No entanto, na maioria dos casos, não há problemas com o uso da reflexão. Se sua única necessidade é inspecionar alguma montagem, eu recomendaria o Mono.Cecil, que é muito leve e rápido

aku
fonte
3

A reflexão é cara devido às muitas verificações que o tempo de execução deve fazer sempre que você solicita um método que corresponda a uma lista de parâmetros. Em algum lugar profundo, existe um código que percorre todos os métodos de um tipo, verifica sua visibilidade, verifica o tipo de retorno e também o tipo de cada parâmetro. Tudo isso custa tempo.

Quando você executa esse método internamente, existe algum código que faz coisas como verificar se você passou uma lista compatível de parâmetros antes de executar o método de destino real.

Se possível, é sempre recomendável que você armazene em cache o identificador do método para reutilizá-lo continuamente no futuro. Como todas as boas dicas de programação, geralmente faz sentido evitar se repetir. Nesse caso, seria um desperdício procurar continuamente o método com determinados parâmetros e executá-lo sempre.

Dê uma olhada na fonte e veja o que está sendo feito.

mP.
fonte
3

Como em tudo, trata-se de avaliar a situação. No DotNetNuke, existe um componente bastante básico chamado FillObjectque usa reflexão para preencher objetos de datarows.

Esse é um cenário bastante comum e há um artigo no MSDN, Usando o Reflection para vincular objetos de negócios a controles de formulário do ASP.NET, que aborda os problemas de desempenho.

Desempenho à parte, uma coisa que eu não gosto em usar a reflexão nesse cenário específico é que ele tende a reduzir a capacidade de entender o código rapidamente, o que para mim não parece valer o esforço quando você considera que também perde a compilação segurança de tempo, em oposição a conjuntos de dados fortemente tipados ou algo como LINQ to SQL .

lomaxx
fonte
2

O Reflexo não diminui drasticamente o desempenho do seu aplicativo. Você pode fazer algumas coisas mais rapidamente, sem usar a reflexão, mas se a Reflexão for a maneira mais fácil de obter alguma funcionalidade, use-a. Você sempre pode refatorar seu código do Reflection se ele se tornar um problema de desempenho.

Chris Pietschmann
fonte
1

Eu acho que você vai achar que a resposta é, depende. Não é grande coisa se você quiser colocá-lo em seu aplicativo de lista de tarefas. É importante se você quiser colocá-lo na biblioteca de persistência do Facebook.

tsimon
fonte