Are MEF exports cached or discovering every time on request?

前端 未结 3 1345
伪装坚强ぢ
伪装坚强ぢ 2021-01-05 16:23

If I have one type MyClass, register with

[Export(typeof(Myclass))] attribute, and

[PartCreationPolicy(CreationPolicy.Shared)]

相关标签:
3条回答
  • 2021-01-05 16:46

    will MEF do global lookup again or it caches somewhere internally

    Yes, MEF perfoms some caching and widely uses lazy initialization, if you question is about MEF performance:

    1) metadata (composable parts, export definitions and import definitions) is cached. Example:

    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) exported values are cached 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;
        }
    }
    

    Of course, when using CreationPolicy.NonShared, exported value becomes created again and again, when you requesting it. But even in this case "global lookup" isn't performed, because metadata is cached anyway.

    0 讨论(0)
  • 2021-01-05 16:47

    Although the values/metadata might be partially cached, doing some performance testing shows that some lookup is performed every time a call to GetExportedValue is made. So if you have many calls where you need to get the value, you should do the caching yourself.

    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
        {
        }
    }
    

    For more variations, look at this gist: https://gist.github.com/DanielRose/d79f0da2ef61591176ce

    On my computer, Windows 7 x64, .NET 4.5.2:

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

    Using MEF 2 from NuGet:

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

    In the actual application where I work, this made the application 6x slower.

    0 讨论(0)
  • 2021-01-05 16:50

    It does a lookup every time, when you use [PartCreationPolicy(CreationPolicy.NonShared)]. You then have to implement the caching yourself.

    The default implementation is using a Singleton pattern. This equals the attribute [PartCreationPolicy(CreationPolicy.Shared)]. This is the best practice.

    For more information, read http://blogs.microsoft.co.il/blogs/bnaya/archive/2010/01/09/mef-for-beginner-part-creation-policy-part-6.aspx

    0 讨论(0)
提交回复
热议问题