当使用PLINQ Extensions时,线程标识是否被传输?
本文关键字:是否 标识 传输 线程 PLINQ Extensions | 更新日期: 2023-09-27 18:16:14
我使用. asparallel (). forall()在ASP的上下文中并行枚举一个集合。网络请求。枚举方法依赖于System.Threading.Thread.CurrentPrincipal.
我可以依赖于使用它们的单独线程将它们的System.Threading.Thread.CurrentPrincipal设置为正在处理ASP的线程的HttpContext.Current.User吗?. NET请求还是我需要自己管理?
问这个问题的另一种方式是,PLINQ使用的线程是否继承了调用该操作的线程的身份?不,标识不会自动传播到这些工作线程。如果,事实上,你正在使用的组件是HttpContext.User
,你可以做的是捕获当前的,"环境"HttpContext
实例在你的"主"线程和传播它到你的工作线程。它看起来像这样:
HttpContext currentHttpContext = HttpContext.Current;
myWorkItems.AsParallel().ForAll(wi =>
{
HttpContext.Current = currentHttpContext;
try
{
// anything called from here out will find/use the context of your original ASP.NET thread
}
finally
{
// Disassociate the context from the worker thread so that it is not held on to beyond its official lifetime
HttpContext.Current = null;
}
});
这是有效的,因为HttpContext.Current
是由线程静态支持的,所以每个工作线程将从主线程分配实例,并且从该点开始在其上完成的任何工作将被视为当前实例。
现在,您必须意识到HttpContext
和它的相关类不是被设计为线程安全的,所以这是一个hack。如果您只从属性中读取,这不是问题。如果你不使用依赖于HttpContext.Current
的组件,那么不设置它会"更干净",而是直接在worker中使用捕获的currentHttpContext
变量。
最后,如果您真正需要的是将当前主体传播到工作线程,那么您可以使用相同的方法:
Principal logicalPrincipal = Thread.CurrentPrincipal;
myWorkItems.AsParallel().ForAll(wi =>
{
Principal originalWorkerThreadPrincipal = Thread.CurrentPrincipal;
Thread.CurrentPrincipal = logicalPrincipal;
try
{
// anything called from here out will find the principal from your original thread
}
finally
{
// Revert to the original identity when work is complete
Thread.CurrentPrincipal = originalWorkerThreadPrincipal;
}
});
这是CurrentPrincipal
背后的实现
public static IPrincipal CurrentPrincipal
{
get
{
lock (CurrentThread)
{
IPrincipal threadPrincipal = CallContext.Principal;
if (threadPrincipal == null)
{
threadPrincipal = GetDomain().GetThreadPrincipal();
CallContext.Principal = threadPrincipal;
}
return threadPrincipal;
}
}
set { CallContext.Principal = value; }
}
所有新创建的线程都将为null,它将从应用程序域获取。所以应该没问题。然而,你需要注意文化。它不会从起始线程派生。参见:并行编程、PLINQ和全球化
当通过.AsParallel()边界传递Principal时要注意的一个微妙的事情:您的序列在哪里具体化?
这不是.ForAll()的问题,但是考虑另一个场景:
var result = items.AsParallel().Select(MyTransform);
然后你在其他地方传递result,以便它跨越线程边界(这很可能,说,如果你从WCF动作方法返回它)。
在这种情况下,当MyTransform被应用时,线程。CurrentPrincipal value可能包含一些意想不到的内容。
因此,这里的解决方法是当场实现查询(通过调用. toarray ()、. tolist ()等)