使用PLINQ Extensions时是否传输了线程标识?

Joe*_*ger 8 c# asp.net multithreading plinq

我正在使用.AsParallel().ForAll()在ASP.NET请求的上下文中并行枚举一个集合.枚举方法依赖于System.Threading.Thread.CurrentPrincipal.

我可以依赖于用于将System.Threading.Thread.CurrentPrincipal设置为处理ASP.NET请求的线程的HttpContext.Current.User的单个线程,还是我需要自己管理?

问这个问题的另一种方法是PLINQ使用的线程是否继承了调用该操作的线程的标识?

Dre*_*rsh 11

不,身份不会自动传播到这些工作线程.实际上,如果您正在使用的组件是HttpContext.User您可以捕获HttpContext"main"线程中的当前"环境" 实例并将其传播到工作线程.这看起来像这样:

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;
    }
});
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为它HttpContext.Current是由线程静态支持的,因此每个工作线程都将从主线程中分配实例,并且从该点开始对其执行的任何工作都会将其视为当前实例.

现在,你必须要知道HttpContext它的相关类并不是设计为线程安全的,所以这有点像黑客.如果你只是从房产中读取这不是一个真正的问题.如果你没有使用依赖的组件,HttpContext.Current那么不设置它就会"更干净",而只是currentHttpContext直接在worker中使用捕获的变量.

最后,如果您真正需要的是将当前主体传播到工作线程,那么您可以使用相同的方法来实现:

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;
    }
});
Run Code Online (Sandbox Code Playgroud)