C#:向ASP.NET中的Parallel.ForEach()添加上下文
我有一个带有静态get属性的静态类,在该属性中,我执行以下操作:C#:向ASP.NET中的Parallel.ForEach()添加上下文,c#,asp.net,multithreading,parallel-processing,C#,Asp.net,Multithreading,Parallel Processing,我有一个带有静态get属性的静态类,在该属性中,我执行以下操作: // property body { // HttpContext.Current is NOT null ... Parallel.ForEach(files, file => { // HttpContext.Current is null var promo = new Promotion(); ... }); ...
// property body
{
// HttpContext.Current is NOT null
...
Parallel.ForEach(files, file =>
{
// HttpContext.Current is null
var promo = new Promotion();
...
});
...
// HttpContext.Current is NOT null
}
在视图使用此属性之前,此静态类不会进行类型初始化
问题在于,Promotion
的静态构造函数使用HttpContext.Current
,该构造函数在Parallel.ForEach()
中第一次创建new Promotion()
时初始化。当promo
在此Parallel.ForEach()
范围内实例化时,HttpContext.Current
为null
,因此new Promotion()
会导致异常
HttpContext.Current
在静态get属性中不为null,因为在视图使用它之前不会调用它(因此存在HttpContext.Current
)
如果Promotion
在其实例中而不是在其静态成员中使用HttpContext.Current
,我可能只需将HttpContext.Current
传递到new Promotion()
构造函数中:
var context = HttpContext.Current;
Parallel.ForEach(files, file =>
{
var promo = new Promotion(context);
});
但是由于static
Promotion的成员需要HttpContext.Current,我不能。我可能会重新设计升级
类,以将需要它的静态成员更改为实例成员,但它们是静态的,这是有原因的——如果每次实例化新升级
时都必须在每个实例上定义所有静态成员,则会造成很大的性能损失
这方面可能的解决办法是什么?我没有意识到
HttpContext.Current
在Parallel.ForEach()
HttpContext.Current的范围内将为null,因为它在“非web线程”中运行。如果您使用newthread(…)
来分叉一些代码,它将完全相同。TPL在某种程度上隐藏了这一点,但您仍然需要认识到,并行.ForEach
中的每个迭代都可能在不同的线程中运行,并相应地处理它
特别是,如果您想在web请求之外使用某些类或方法(Parallel.ForEach就是这样一种用法),您就不能使用HttpContext.Current。一种解决方法是在构造函数中显式传递HttpContext(或HttpContextBase,以提高可测试性)(或作为方法参数)
简而言之:您需要打破使用HttpContext.Current的静态模式。正如Mauricio指出的,
HttpContext.Current取决于当前执行的线程。静态构造函数依赖于诸如HttpContext.Current
这样的固有瞬态值,这让我感到很不寻常,但这可能不是您的想法
如果您可以更改<代码>促销>代码>类,那将是我考虑的第一个选项。
如果不是,您需要在
HttpContext.Current
仍然有效的位置强制执行Promotion
的类型初始化。要了解什么强制初始化类型,请阅读
一个选项可以是创建一个虚拟的Promotion
对象(在整个程序中只创建一次就足够了)。如果这不是一个选项,您可以尝试通过使用反射读取属性。我不知道这是否会强制类型初始化,但我想是的 只需将Parallel.ForEach调用外部的任何上下文向下传递到依赖于所述上下文的内部调用的任何函数中即可
var context = HttpContext.Current;
Parallel.ForEach(items, item =>
{
DoSomething(item, context);
}
);
private static void DoSomething(item, context = null) {
if (context == null) context = HttpContext.Current;
...
}
我喜欢回退到null,这样我就不必一直担心传递上下文。我只确保在从另一个线程调用时,我的函数需要上下文,然后我就把它放在那里。它不起作用,因为在foreach中创建了一个新线程,所以上下文为空。即使创建一个方法DoSomething来设置curren上下文,上下文仍然为空。当第一次接触类的代码时,升级的静态成员将只初始化一次。。。。它们如何依赖于HttpContext.Current
?促销的源代码是否在您的控制之下?