Ninject, Parallel.ForEach и InThreadScope () - PullRequest
5 голосов
/ 27 марта 2012

Буду признателен за предложения по реализации следующего с Ninject:

У меня есть многопоточное приложение.Он запускает одновременно около 20 очень независимых потоков.После запуска приложения я связываю интерфейс с объектом через Ninject с помощью InThreadScope (), и все работает хорошо.Каждый поток получает объект, специфичный для его потока (конструктор каждого объекта создает несколько флагов, специфичных для потока).

Большая часть работы, выполняемой каждым потоком, заключается в ожидании завершения процесса хранения данных.Итак, чтобы еще больше оптимизировать потоки, мы реализовали логику Parallel.ForEach в основных 20 потоках.Я хотел бы, чтобы потоки, сгенерированные Paralell.ForEach, получали ту же привязку, что и их родительский поток.Однако я не могу просто повторно привязать интерфейс к соответствующему объекту внутри Parallel.ForEach, я просто не знаю, что такое связанный объект - внутри Paralell. ForEach я могу работать только с интерфейсом.

Что такоеправильный способ получения привязок из Ядра во время выполнения, до запуска Paralell.ForEach и повторной привязки их в цикле?

Редактировать: пытается включить подробную логику / псевдокод:

Каждый запущенный поток выполняет что-то вроде этого:

Kernel.Bind<ILoggingContext>().To<Application1LoggingContext>().InThreadScope();

Однако, когда запускается Parallel.ForEach () из отдельных потоков, у меня больше нет доступа к объекту Application1LoggingContext и я не могу выполнить повторное связываниеILoggingContext к нему.Это связано с тем, что Parallel.ForEach () выполняется из базового класса и не знает, с каким Application LoggingContext он должен быть связан.Это делается внутри каждого приложения, после запуска больших 20 потоков.

Я хотел бы изменить базовый класс, который раскручивает Parallel.ForEach (), и обеспечить внутри каждого вновь созданного Parallel.Поток .ForEach, в котором ILoggingContext по-прежнему привязан к Application1LoggingContext - обычно, так что я могу выполнить следующее:

var ctx = Kernel.Get<ILoggingContext>();

Ответы [ 2 ]

1 голос
/ 06 апреля 2012

Похоже, я понял это. Вот общий способ перепривязать привязку внутри Parallel.Foreach. В зависимости от сложности / количества привязок, это может или не может работать для вас из коробки

var logBinding = Kernel.GetBindings(typeof(ILoggingContext)).FirstOrDefault();

Parallel.ForEach(items, n =>
                            {
                                if (Kernel.GetBindings(typeof(ILoggingContext)).Count() == 0 && logBinding != null)
                                    Kernel.AddBinding(logBinding);

                                //do stuff
                                }
                            });
0 голосов
/ 02 апреля 2012

Можете ли вы захватить ILoggingContext в замыкании для передачи в итерации Parallel.ForEach ()?

Ваш метод базового класса (StartUpBase.Start()), который запускает Parallel.ForEach (), может быть вызван изконтекстно-зависимый производный тип (StartUpApplication1) в родительском потоке.Производный тип может получить ILoggingContext из ядра Ninject, которое вы хотите передать дочерним элементам, и передать его в метод базового класса, который затем передает его в параллельные итерации через замыкание: например:

abstract class StartUpBase
{
    public abstract void Start();

    protected void StartApplication<T>(ILoggingContext ctx, IEnumerable<T> enumerableWork)
    {
        Parallel.ForEach(enumerableWork, iter =>
            {
                // this code can refer to ctx e.g.
                ctx.Log(message);
            });
    }
}

internal class StartupApplication1<T> : StartUpBase
{
    // setup of this is elsewhere...
    private IEnumerable<T> _enumerableWork;

    public override void Start()
    {
        ILoggingContext ctx = Kernel.Bind<ILoggingContext>()
            .To<Application1LoggingContext>().InThreadScope();
        StartApplication(ctx, _enumerableWork);
    }
}
...