【问题标题】:Are MEF exports cached or discovering every time on request?每次请求时,MEF 导出是否都被缓存或发现?
【发布时间】:2013-01-11 08:45:21
【问题描述】:

如果我有一种类型的 MyClass,请注册

[Export(typeof(Myclass))] 属性和

[PartCreationPolicy(CreationPolicy.Shared)]

[PartCreationPolicy(CreationPolicy.NonShared)]

后来尝试调用

compositionContainer.GetExportedValue<Myclass>() 多次。

问题:第一次调用时,我将通过 MEF 获取我的注册课程 - 查找所有已注册的程序集,然后尝试找到一个已注册的合同。问题是关于第二次等等 - MEF 会再次进行全局查找还是在内部某个地方缓存?

【问题讨论】:

    标签: c# .net wpf mef


    【解决方案1】:

    MEF 会再次进行全局查找还是在内部某个地方缓存

    是的,如果您对 MEF 性能有疑问,MEF 会执行一些缓存并广泛使用延迟初始化:

    1) 缓存元数据(可组合部件、导出定义和导入定义)。示例:

    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) 导出的 也被缓存:

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

    当然,当使用CreationPolicy.NonShared 时,导出值会在您请求时一次又一次地创建。但即使在这种情况下,也不会执行“全局查找”,因为无论如何都会缓存元数据。

    【讨论】:

    • 感谢您的解释!
    • 这是不完整的,因为在每次调用时仍会执行一些查找。因此,如果有很多对 GetExportedValue 的调用,则应该进行客户端缓存。
    【解决方案2】:

    当您使用[PartCreationPolicy(CreationPolicy.NonShared)] 时,它每次都会进行查找。然后你必须自己实现缓存。

    默认实现是使用单例模式。这等于属性[PartCreationPolicy(CreationPolicy.Shared)]这是最佳做法

    欲了解更多信息,请阅读http://blogs.microsoft.co.il/blogs/bnaya/archive/2010/01/09/mef-for-beginner-part-creation-policy-part-6.aspx

    【讨论】:

    • “它每次都进行查找” - 证明?
    • 我认为,这个问题不在于缓存具体的导出值。
    • 其实我想知道,如果我在很多视图中广泛使用一些[Import]MyClassObject,它会在多长时间内查找第一个&scond&so的时间。
    【解决方案3】:

    虽然值/元数据可能被部分缓存,但进行一些性能测试表明,每次调用 GetExportedValue 时都会执行一些查找。所以如果你有很多调用需要获取值,你应该自己做缓存。

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

    有关更多变化,请查看此要点:https://gist.github.com/DanielRose/d79f0da2ef61591176ce

    在我的电脑上,Windows 7 x64,.NET 4.5.2:

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

    使用来自 NuGet 的 MEF 2:

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

    在我工作的实际应用程序中,这使应用程序慢了 6 倍。

    【讨论】:

      猜你喜欢
      • 2017-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-22
      相关资源
      最近更新 更多