Ninject,Parallel.ForEach和InThreadScope()

时间:2012-03-27 03:04:13

标签: c# multithreading inversion-of-control ninject

我希望有关如何使用Ninject实现以下内容的建议:

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

每个线程所做的大部分工作都在等待数据存储完成进程。因此,为了进一步优化线程,我们在主要的20个线程中实现了Parallel.ForEach逻辑。我想让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 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

你能在闭包中捕获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);
    }
}