Ninject, Parallel.ForEach and InThreadScope()



我非常感谢关于如何使用Ninject实现以下内容的建议:

我有一个多线程应用程序。它同时运行大约20个非常独立的线程。在应用程序启动时,我使用InThreadScope()通过Ninject将接口绑定到对象,一切都很好。每个线程接收特定于其线程的对象(每个对象的构造函数实例化许多特定于线程的标志)。

每个线程所做的大部分工作都是等待数据存储完成进程。因此,为了进一步优化线程,我们在主要的20个线程中实现了Parallel.ForEach逻辑。我希望Paralell.ForEach生成的线程能够获得与其父线程相同的绑定。然而,我不能简单地将接口重新绑定到Parallel.ForEach中的适当对象。对于Each,我根本不知道绑定的对象是什么——在Paralell.ForEach中,我只能使用接口。

在Paralell.ForEach启动并在循环中一般性地重新绑定之前,在运行时从内核中检索绑定的正确方法是什么?

编辑:尝试包含详细的逻辑/伪代码:

每个线程启动后都会执行以下操作:

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

然而,当Parallel.ForEach()从各个线程内部启动时,我不再能够访问Application1LoggingContext对象,也无法将ILogging上下文重新绑定到它。这是因为Parallel.FordEach(,在开始大的20个线程时。

我想修改基类,即启动Parallel.ForEach()的基类,并确保在Parallel.For每个线程新创建的每个线程内部,ILoggingContext仍然绑定到Application1LoggingContext-一般来说,这样我就可以执行以下操作:

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

看起来我已经明白了。以下是在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
                                }
                            });

您能在闭包中捕获ILoggingContext以传递给Parallel.ForEach()迭代吗?

启动Parallel.ForEach()的基类方法(StartUpBase.Start())可以从父线程上的上下文感知派生类型(StartUpApplication1)调用。派生类型可以从Ninject内核获取ILoggingContext,您希望将其传递给子级,并将其传递到基类方法,然后基类方法通过闭包将其传递至并行迭代:例如:

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);
    }
}

最新更新