使用 PLINQ 扩展时是否会传输线程标识?
我正在使用 .AsParallel().ForAll() 在 ASP.NET 请求上下文中并行枚举集合。枚举方法依赖于System.Threading.Thread.CurrentPrincipal。
我是否可以依赖用于将 System.Threading.Thread.CurrentPrincipal 设置为处理 ASP.NET 请求的线程的 HttpContext.Current.User 的各个线程,还是需要我自己进行管理?
提出问题的另一种方式是 PLINQ 使用的线程是否继承调用该操作的线程的标识?
I am using .AsParallel().ForAll() to enumerate a collection in parallel in the context of an ASP.NET request. The enumeration method relies on System.Threading.Thread.CurrentPrincipal.
Can I rely on the individual threads used to have their System.Threading.Thread.CurrentPrincipal set to the HttpContext.Current.User of the thread that is processing the ASP.NET Request or do I need to manage that myself?
Another way of asking the question is do the threads used by PLINQ inherit the identity of the thread that invoked the operation?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不,身份不会自动传播到这些工作线程。事实上,如果您使用的组件是
HttpContext.User
,您可以做的就是捕获“主”线程中当前的“环境”HttpContext
实例并传播它到你的工作线程。这看起来像这样:这是有效的,因为
HttpContext.Current
由线程静态支持,因此每个工作线程都将从主线程分配该实例,并且从该点开始对其执行的任何工作都将将其视为当前实例。现在,您必须意识到
HttpContext
及其相关类并未设计为线程安全的,因此这有点像黑客。如果您只读取属性,这并不是真正的问题。如果您没有使用依赖于HttpContext.Current
的组件,那么不设置它而是直接在工作线程中使用捕获的currentHttpContext
变量会更“干净”。最后,如果您真正需要的只是将当前主体传播到工作线程,那么您可以这样做,而不是使用相同的方法:
No, the identity will not be propagated to these worker threads automatically. If, in fact, the components you are using are
HttpContext.User
what you can do is capture the current, "ambient"HttpContext
instance in your "main" thread and propagate it to your worker threads. That would look something like this:This works because
HttpContext.Current
is backed by a thread static, so every worker thread will be assigned the instance from your main thread and any work done on it from that point will see that as the current instance.Now, you have to be aware that
HttpContext
and its related classes were not designed to be thread safe, so this is a bit of a hack. If you're only reading from properties this isn't really a problem. If you are not using components that rely onHttpContext.Current
then it would be "cleaner" to not set that and instead just use the capturedcurrentHttpContext
variable directly in the worker.Finally, if all you really need is to propagate the current principal to the worker threads then you can do just that instead using the same approach:
这是
CurrentPrincipal
背后的实现。所有新创建的线程都将具有 null,并且将从应用程序域中获取。所以应该没问题。尽管如此,你还是需要小心文化。它不会从启动线程派生。请参阅:并行编程、PLINQ 和全球化
This is the implementation behind
CurrentPrincipal
All newly created threads will have null and it will be taken from application domain. So it should be ok. Nevertheless you need be careful with culture. It will not be derived from starting thread. See: Parallel Programing, PLINQ and Globalization
通过 .AsParallel() 边界传递 Principal 时需要注意的一件微妙的事情:您的序列在哪里具体化?
这不是 .ForAll() 的问题,但请考虑另一种情况:
然后您将结果传递到其他地方,以便它跨越线程边界(这很可能是这样的) ,如果您从 WCF 操作方法返回它)。
在这种情况下,当应用 MyTransform 时,Thread.CurrentPrincipal 值可能包含意外的内容。
因此,这里的解决方法是当场具体化查询(通过调用 .ToArray()、.ToList() 等)
One subtle thing to notice when passing Principal through .AsParallel() boundary: Where your sequence gets materialized?
This isn't a problem with .ForAll(), but consider another scenario:
Then you're passing result elsewhere so that it crosses thread boundary (which is likely, say, if you're returning it out of WCF action method).
In this case by the time MyTransform gets applied, Thread.CurrentPrincipal value might contain something unexpected.
So, the workaround here is to materialize query on the spot (by calling .ToArray(), .ToList(), etc.)