Parallel.Foreach 中的 Ninject 异常
我有一段代码,它在要处理的项目列表上运行 Parallel.Foreach
。每次迭代都会创建几个对象,每个对象实例化并处理它自己的 Ninject IKernel 实例。当对象完成其工作时,IKernel 将被释放。
也就是说,这段代码在我的 Windows 7、I7 笔记本电脑上运行得非常好。但是,当我将其推送到运行 Windows 2008 的 VPS 时,出现此异常。异常不会在同一次迭代中发生,有时会经历 10 次迭代并抛出异常,有时会经历数百次迭代。显然,这似乎是一个线程问题,但除了我的 VPS 之外,其他任何地方都不会发生这种情况。如果重要的话,它托管在 ASP.NET IIS 中。
System.AggregateException: One or more errors occurred. --->
System.ArgumentOutOfRangeException: Index was out of range.
Must be non-negative and less than the size of the collection.
Parameter name: index
at System.Collections.Generic.List`1.RemoveAt(Int32 index)
at Ninject.KernelBase.Dispose(Boolean disposing)
以下是代码片段:
//Code that creates and disposes the Ninject kernel
using(ninjectInstance = new NinjectInstance())
{
using (var unitOfWork = ninjectInstance.Kernel.Get<NinjectUnitOfWork>())
{
Init();
continueValidation = Validate(tran, ofr);
}
}
public class NinjectInstance : IDisposable
{
public IKernel Kernel { get; private set; }
public NinjectInstance()
{
Kernel = new StandardKernel(
new NinjectSettings() { AllowNullInjection = true },
new NinjectUnitOfWorkConfigModule());
}
public void Dispose()
{
if (Kernel != null)
{
Kernel.Dispose();
}
}
}
编辑 1 有一点是肯定的,这是一个线程安全问题,我不应该为每个应用程序创建多个 IKernel 实例。需要理解如何配置适当的范围以实现实体框架上下文线程安全,同时保留 UoW 类型方法,其中多个业务层类可以在单个线程内的 UoW 范围内共享相同的 EF 上下文。
I have a piece of code that runs a Parallel.Foreach
on a list of items to process. Each iteration creates a couple of objects with each object instantiating and disposing it's own instance of the Ninject IKernel. The IKernel is disposed when the object is done it's work.
That said, this code works perfectly well on my Windows 7, I7 laptop. However when I push it out to my VPS that runs Windows 2008 I get this exception. The exception doesn't happen on the same iteration, sometimes it will get through 10 iterations and throw an exception, other times it will go through hundreds of them. Obviously seems like a threading issue, but it doesn't happen anywhere but my VPS. If it matters this is being hosted in ASP.NET IIS.
System.AggregateException: One or more errors occurred. --->
System.ArgumentOutOfRangeException: Index was out of range.
Must be non-negative and less than the size of the collection.
Parameter name: index
at System.Collections.Generic.List`1.RemoveAt(Int32 index)
at Ninject.KernelBase.Dispose(Boolean disposing)
Here is a snippet of the code:
//Code that creates and disposes the Ninject kernel
using(ninjectInstance = new NinjectInstance())
{
using (var unitOfWork = ninjectInstance.Kernel.Get<NinjectUnitOfWork>())
{
Init();
continueValidation = Validate(tran, ofr);
}
}
public class NinjectInstance : IDisposable
{
public IKernel Kernel { get; private set; }
public NinjectInstance()
{
Kernel = new StandardKernel(
new NinjectSettings() { AllowNullInjection = true },
new NinjectUnitOfWorkConfigModule());
}
public void Dispose()
{
if (Kernel != null)
{
Kernel.Dispose();
}
}
}
Edit 1
One thing is for sure, this is a thread safety issue and I should not be creating more than one instance of IKernel per application. It's a matter of understanding on how to configure the proper scopes in order to accomplish Entity Framework Context thread safety yet preserving the UoW type approach where multiple business layer classes can share the same EF context within the UoW scope within a single thread.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
请参阅 http://groups.google.com/group/ninject/browse_thread/thread /574cd317d609e764
正如我告诉你的,Ninject 的 ctor 不是线程安全的 atm,除非你使用
NOWEB
!如果创建/处置内核多次,您将必须自己同步访问!我仍然建议重新设计你的 UoW 实施!See http://groups.google.com/group/ninject/browse_thread/thread/574cd317d609e764
As I told you Ninject's ctor is not threadsafe atm unless you are using
NOWEB
! If creating/disposing the kernel so many times you will have to synchronize the access yourself! I still suggest to redesign your UoW implementation!看起来
ninjectInstance
是一个实例变量。因此,在并行环境中,ninjectInstance.Dispose()
可能会被调用两次(调用Kernel.Dispose()
不会将 Kernel 属性设置为 null) 对于同一实例,并且由于已经调用了 Kernel.Dispose(),因此该方法失败。也许你想要类似的东西
It seems like
ninjectInstance
is an instance variable. Hence, it's possible that in a parallel environment,ninjectInstance.Dispose()
will be called twice (callingKernel.Dispose()
does not set the Kernel property to null) for the same instance and sinceKernel.Dispose()
is already been called, the method fails.Maybe you wanted something like