Как управлять порядком инициализации модуля в Призме

Вот мои числа:

15170 MyDivRem
29579 DivRem (same code as below)
29579 Math.DivRem
30031 inlined

тест был немного изменен; я добавил присвоение на возвращаемое значение и выполнял сборку конечных версий.

Core 2 Duo 2.4

Мнение:

Вы, казалось, нашли хорошую оптимизацию ;)

9
задан Robert Taylor 24 August 2009 в 20:01
поделиться

5 ответов

Мне не понравилась идея использования ModuleDependency, поскольку это означало бы, что модуль a не загрузится при отсутствии модуля b, когда на самом деле никакой зависимости нет. Вместо этого я создал атрибут priority для украшения модуля:

/// <summary>
/// Allows the order of module loading to be controlled.  Where dependencies
/// allow, module loading order will be controlled by relative values of priority
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class PriorityAttribute : Attribute
{
    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="priority">the priority to assign</param>
    public PriorityAttribute(int priority)
    {
        this.Priority = priority;
    }

    /// <summary>
    /// Gets or sets the priority of the module.
    /// </summary>
    /// <value>The priority of the module.</value>
    public int Priority { get; private set; }
}

Затем я украсил модули следующим образом:

[Priority(200)]
[Module(ModuleName = "MyModule")]
public class MyModule : IModule

Я создал нового потомка DirectoryModuleCatalog:

/// <summary>
/// ModuleCatalog that respects PriorityAttribute for sorting modules
/// </summary>
[SecurityPermission(SecurityAction.InheritanceDemand), SecurityPermission(SecurityAction.LinkDemand)]
public class PrioritizedDirectoryModuleCatalog : DirectoryModuleCatalog
{
    /// <summary>
    /// local class to load assemblies into different appdomain which is then discarded
    /// </summary>
    private class ModulePriorityLoader : MarshalByRefObject
    {
        /// <summary>
        /// Get the priorities
        /// </summary>
        /// <param name="modules"></param>
        /// <returns></returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")]
        public Dictionary<string, int> GetPriorities(IEnumerable<ModuleInfo> modules)
        {
            //retrieve the priorities of each module, so that we can use them to override the 
            //sorting - but only so far as we don't mess up the dependencies
            var priorities = new Dictionary<string, int>();
            var assemblies = new Dictionary<string, Assembly>();

            foreach (ModuleInfo module in modules)
            {
                if (!assemblies.ContainsKey(module.Ref))
                {
                    //LoadFrom should generally be avoided appently due to unexpected side effects,
                    //but since we are doing all this in a separate AppDomain which is discarded
                    //this needn't worry us
                    assemblies.Add(module.Ref, Assembly.LoadFrom(module.Ref));
                }

                Type type = assemblies[module.Ref].GetExportedTypes()
                    .Where(t => t.AssemblyQualifiedName.Equals(module.ModuleType, StringComparison.Ordinal))
                    .First();

                var priorityAttribute =
                    CustomAttributeData.GetCustomAttributes(type).FirstOrDefault(
                        cad => cad.Constructor.DeclaringType.FullName == typeof(PriorityAttribute).FullName);

                int priority;
                if (priorityAttribute != null)
                {
                    priority = (int)priorityAttribute.ConstructorArguments[0].Value;
                }
                else
                {
                    priority = 0;
                }

                priorities.Add(module.ModuleName, priority);
            }

            return priorities;
        }
    }

    /// <summary>
    /// Get the priorities that have been assigned to each module.  If a module does not have a priority 
    /// assigned (via the Priority attribute) then it is assigned a priority of 0
    /// </summary>
    /// <param name="modules">modules to retrieve priorities for</param>
    /// <returns></returns>
    private Dictionary<string, int> GetModulePriorities(IEnumerable<ModuleInfo> modules)
    {
        AppDomain childDomain = BuildChildDomain(AppDomain.CurrentDomain);
        try
        {
            Type loaderType = typeof(ModulePriorityLoader);
            var loader =
                (ModulePriorityLoader)
                childDomain.CreateInstanceFrom(loaderType.Assembly.Location, loaderType.FullName).Unwrap();

            return loader.GetPriorities(modules);
        }
        finally
        {
            AppDomain.Unload(childDomain);
        }
    }

    /// <summary>
    /// Sort modules according to dependencies and Priority
    /// </summary>
    /// <param name="modules">modules to sort</param>
    /// <returns>sorted modules</returns>
    protected override IEnumerable<ModuleInfo> Sort(IEnumerable<ModuleInfo> modules)
    {
        Dictionary<string, int> priorities = GetModulePriorities(modules);
        //call the base sort since it resolves dependencies, then re-sort 
        var result = new List<ModuleInfo>(base.Sort(modules));
        result.Sort((x, y) =>
            {
                string xModuleName = x.ModuleName;
                string yModuleName = y.ModuleName;
                //if one depends on other then non-dependent must come first
                //otherwise base on priority
                if (x.DependsOn.Contains(yModuleName))
                    return 1; //x after y
                else if (y.DependsOn.Contains(xModuleName))
                    return -1; //y after x
                else 
                    return priorities[xModuleName].CompareTo(priorities[yModuleName]);
            });

        return result;
    }
}

Наконец, я изменил bootstrapper, чтобы использовать этот новый каталог:

    /// <summary>Where are the modules located</summary>
    /// <returns></returns>
    protected override IModuleCatalog GetModuleCatalog()
    {
        return new PrioritizedDirectoryModuleCatalog() { ModulePath = @".\Modules" };
    }

Я не уверен, что вещи с загрузкой сборки - это лучший способ сделать вещи, но это, кажется, работает...

13
ответ дан 4 December 2019 в 11:07
поделиться

Вы можете использовать атрибут ModuleDependency в своем классе модуля, чтобы сообщить загрузчику, что ваш модуль зависит от других модулей:

[ModuleDependency("SomeModule")]
[ModuleDependency("SomeOtherModule")]
public class MyModule : IModule
{
}
3
ответ дан 4 December 2019 в 11:07
поделиться

в AddModule () вызовите в Bootstrapper, вы можете указать зависимость. Итак, вы можете сказать, что A зависит от B, зависит от C, и это будет определять порядок загрузки.

http://msdn.microsoft.com/en-us/magazine/cc785479.aspx

0
ответ дан 4 December 2019 в 11:07
поделиться

Вы можете заменить IModuleInitializer по умолчанию на экземпляр пользовательского класса, который вместо инициализации модулей сразу после их загрузки сохраняет их в списке модулей. Когда все модули загружены, вы инициализируете их в любом порядке.

Как этого добиться:

1) В загрузчике переопределите метод ConfigureContainer , чтобы заменить значение по умолчанию IModuleInitializer для экземпляра класса MyModuleInitializer , но с сохранением инициализатора по умолчанию с именем (например, defaultModuleInitializer ):


protected override void ConfigureContainer()
{
    base.ConfigureContainer();
    var defaultContainer = Container.Resolve<IModuleInitializer>();
    Container.RegisterInstance<IModuleInitializer>("defaultModuleInitializer", defaultContainer);
    Container.RegisterType<IModuleInitializer, MyModuleInitializer>(new ContainerControlledLifetimeManager());
}


2) Создайте MyModuleInitializer класс, который выполняет желаемую процедуру «сначала сохранить все, затем отсортировать и инициализировать»:


public class MyModuleInitializer : IModuleInitializer
{
    bool initialModuleLoadCompleted = false;
    IModuleInitializer defaultInitializer = null;
    List<ModuleInfo> modules = new List<ModuleInfo>();

    public MyModuleInitializer(IUnityContainer container)
    {
        defaultInitializer = container.Resolve<IModuleInitializer>("defaultModuleInitializer");
    }

    public void Initialize(ModuleInfo moduleInfo)
    {
        if(initialModuleLoadCompleted) {
            //Module loaded on demand after application startup - use the default initializer
            defaultInitializer.Initialize(moduleInfo);
            return;
        }

        modules.Add(moduleInfo);

        if(AllModulesLoaded()) {
            SortModules();
            foreach(var module in modules) {
                defaultInitializer.Initialize(module);
            }
            modules = null;
            initialModuleLoadCompleted = true;
        }
    }

    private bool AllModulesLoaded()
    {
        //Here you check whether all the startup modules have been loaded
        //(perhaps by looking at the module catalog) and return true if so
    }

    private void SortModules()
    {
        //Here you sort the "modules" list however you want
    }
}

Обратите внимание, что после загрузки всех модулей запуска этот класс возвращается к простому вызову инициализатора по умолчанию. Если это не то, что вам нужно, измените класс соответствующим образом.

2
ответ дан 4 December 2019 в 11:07
поделиться

Я решил эту проблему с помощью атрибута ModuleDependency, и он сработал как шарм

1
ответ дан 4 December 2019 в 11:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: