2013-01-11 6 views
5

Jeśli mam jeden typ MojaKlasa, zarejestrować sięCzy MEF eksportuje się do pamięci podręcznej lub odkrywa za każdym razem na żądanie?

[Export(typeof(Myclass))] atrybutu, a

[PartCreationPolicy(CreationPolicy.Shared)]

lub

[PartCreationPolicy(CreationPolicy.NonShared)]

a później próby wywołania

compositionContainer.GetExportedValue<Myclass>() wiele razy.

Pytanie: przy pierwszym połączeniu otrzymam zarejestrowaną klasę za pośrednictwem MEF - llokup wszystkich zarejestrowanych zespołów, a następnie spróbuję znaleźć jedną zarejestrowaną umowę. Pytanie brzmi po raz drugi i tak dalej - czy MEF ponownie zrobi globalne wyszukiwanie, czy też gdzieś w pamięci wewnętrznej?

Odpowiedz

7

będzie MEF zrobić globalne wyszukiwanie ponownie lub buforuje gdzieś wewnętrznie

Tak, MEF perfoms jakieś buforowanie i szeroko wykorzystuje leniwe inicjowanie, jeśli pytanie jest o Działanie MEF:

1) metadane (części składowe, definicje eksportu i definicje importu) są buforowane. Przykład:

public override IEnumerable<ExportDefinition> ExportDefinitions 
{ 
    get 
    { 
     if (this._exports == null) 
     { 
      ExportDefinition[] exports = this._creationInfo.GetExports().ToArray<ExportDefinition>(); 
      lock (this._lock) 
      { 
       if (this._exports == null) 
       { 
        this._exports = exports; 
       } 
      } 
     } 
     return this._exports; 
    } 
} 

2) eksportowane wartości są buforowane TOO:

public object Value 
{ 
    get 
    { 
     if (this._exportedValue == Export._EmptyValue) 
     { 
      object exportedValueCore = this.GetExportedValueCore(); 
      Interlocked.CompareExchange(ref this._exportedValue, exportedValueCore, Export._EmptyValue); 
     } 
     return this._exportedValue; 
    } 
} 

Oczywiście, przy użyciu CreationPolicy.NonShared, eksportowane wartość staje się ponownie i ponownie utworzony, gdy zwracając się do niej. Ale nawet w tym przypadku "globalne wyszukiwanie" nie jest wykonywane, ponieważ metadane są przechowywane w pamięci podręcznej.

+0

Dzięki za wyjaśnienie! –

+0

To jest niekompletne, w tym sensie, że niektóre wyszukiwania są nadal wykonywane przy każdym połączeniu. Czyniąc buforowanie po stronie klienta, jeśli jest wiele wywołań do 'GetExportedValue' powinno być zrobione. –

0

Wykonuje wyszukiwanie za każdym razem, gdy używasz [PartCreationPolicy(CreationPolicy.NonShared)]. Następnie musisz sam wdrożyć buforowanie.

Domyślną implementacją jest użycie wzorca Singleton. Jest to równy atrybutowi [PartCreationPolicy(CreationPolicy.Shared)]. To jest najlepsza praktyka.

Aby uzyskać więcej informacji, przeczytaj http://blogs.microsoft.co.il/blogs/bnaya/archive/2010/01/09/mef-for-beginner-part-creation-policy-part-6.aspx

+0

"Sprawdza się za każdym razem" - dowód? – Dennis

+0

Dziękuję, że mnie obudziłeś. Moja odpowiedź była niekompletna. Rozproszono mnie ... – Jacco

+0

Myślę, że to pytanie nie dotyczy buforowania konkretnej wartości eksportowej. – Dennis

0

Mimo że wartości/metadane mogą być częściowo buforowane, wykonanie pewnych testów wydajnościowych pokazuje, że niektóre wyszukiwania są wykonywane za każdym razem, gdy wykonywane jest wywołanie GetExportedValue. Więc jeśli masz wiele połączeń, w których musisz uzyskać wartość, powinieneś sam wykonać buforowanie.

namespace MEFCachingTest 
{ 
    using System; 
    using System.ComponentModel.Composition; 
    using System.ComponentModel.Composition.Hosting; 
    using System.ComponentModel.Composition.Primitives; 
    using System.Diagnostics; 
    using System.Reflection; 

    public static class Program 
    { 
     public static CompositionContainer Container { get; set; } 
     public static ComposablePartCatalog Catalog { get; set; } 

     public static ExportedClass NonCachedClass 
     { 
      get 
      { 
       return Container.GetExportedValue<ExportedClass>(); 
      } 
     } 

     private static ExportedClass cachedClass; 
     public static ExportedClass CachedClass 
     { 
      get 
      { 
       return cachedClass ?? (cachedClass = Container.GetExportedValue<ExportedClass>()); 
      } 
     } 

     public static void Main() 
     { 
      Catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); 
      Container = new CompositionContainer(Catalog); 

      const int Runs = 1000000; 
      var stopwatch = new Stopwatch(); 

      // Non-Cached. 
      stopwatch.Start(); 
      for (int i = 0; i < Runs; i++) 
      { 
       var ncc = NonCachedClass; 
      } 

      stopwatch.Stop(); 
      Console.WriteLine("Non-Cached: Time: {0}", stopwatch.Elapsed); 

      // Cached. 
      stopwatch.Restart(); 
      for (int i = 0; i < Runs; i++) 
      { 
       var cc = CachedClass; 
      } 

      stopwatch.Stop(); 
      Console.WriteLine(" Cached: Time: {0}", stopwatch.Elapsed); 
     } 
    } 

    [Export] 
    [PartCreationPolicy(CreationPolicy.Shared)] 
    public class ExportedClass 
    { 
    } 
} 

uzyskać więcej odmian, spojrzeć na ten GIST: https://gist.github.com/DanielRose/d79f0da2ef61591176ce

Na moim komputerze, Windows 7 x64, .NET 4.5.2.

Non-Cached: Time: 00:00:02.1217811 
    Cached: Time: 00:00:00.0063479 

Stosując MEF 2 od Nuget:

Non-Cached: Time: 00:00:00.2037812 
    Cached: Time: 00:00:00.0023358 

W rzeczywistym zastosowaniu, gdzie działa, to od stosowania 6x wolniej.

Powiązane problemy