简体   繁体   English

线程静态,ASP.NET和异步处理程序

[英]Thread Static, ASP.NET and Async handlers

Please consider these sceanrios: 请考虑这些sceanrios:

  1. An async .ashx handler 异步.ashx处理程序
  2. A async .asmx web-service method 异步.asmx Web服务方法
  3. A sync MVC 5 controller action method 同步MVC 5控制器动作方法

I am trying to figure out a way to set "logical thread" specific data that can be accessed consistently during a "logical" http request, ie if the data was set on the thread in the "BeginExecute" part of which-ever async handler you would consider, that data is available in the "EndExecute" part of that asnc handler even if ASP.NET executes the "EndExecute" part on a different OS/.Net thread. 我试图找出一种方法来设置“逻辑”特定数据,这些数据可以在“逻辑”http请求期间一致地访问,即,如果数据是在“BeginExecute”部分中的线程中设置的,那么该异步处理程序你会想,即使ASP.NET在不同的OS / .Net线程上执行“EndExecute”部分,该数据也可以在该asnc处理程序的“EndExecute”部分中获得。

Moreover, I am expecting that the data set in the "BeginExecute" part on whatever OS/.Net thread it was on is NOT available on a subsequent http request if the second request is assigned the thread that was earlier assigned to first http request when it was in "BeginExecute" portion but this thread freed up as the first http request went in its async operation (and its possibly still completing its async operation). 此外,我希望在第二个请求被分配给先前分配给第一个http请求的线程的时候,在随后的http请求中,在“BeginExecute”部分中设置的任何OS / .Net线程中的数据都不可用。它位于“BeginExecute”部分,但是当第一个http请求进入异步操作时,该线程被释放(并且它可能仍在完成其异步操作)。

I believe the word "logical thread" or "logical thread context" in .Net actually means the same "logical" flow of operation that I have mentioned (and not the underlying OS/.Net thread that keeps getting re-assigned). 我相信.Net中的“逻辑线程”或“逻辑线程上下文”这个词实际上意味着我提到的相同的“逻辑”操作流程(而不是继续重新分配的底层OS / .Net线程)。 If you look at it from a workflow perspective, each http request is a new "logical" operation (even if multiple users invoke the same web-service sequentially or in parallel, each request is a new and separte logical operation), and in this meaning, the "logical" operation is one-time and cannot repeat. 如果从工作流角度来看,每个http请求都是一个新的“逻辑”操作(即使多个用户按顺序或并行调用相同的Web服务,每个请求都是一个新的和部分逻辑操作),并且在此意思是,“逻辑”操作是一次性的,不能重复。 However the same underlying OS/.Net threads can be mapped to "logical" operations as they arrive based on their availability. 但是,相同的底层OS / .Net线程可以根据其可用性到达时映射到“逻辑”操作。

Additionally I want to expose this data as HttpContext.Current sort of static property. 另外,我想将此数据公开为HttpContext.Current类的静态属性。 To some people this may come as a surprise, but HttpContext.Current does not work correctly if you are using for example async .asmx web-service methods. 对于某些人来说,这可能会让人感到惊讶,但如果您使用的是异步.asmx Web服务方法,则HttpContext.Current无法正常工作。 I am sure I have read content on web which says HttpContext.Current should always return correct HttpContext, but I have seen it as null in EndExecuteMethod of .asmx web-methods. 我确信我已经阅读了网上的内容,其中说HttpContext.Current应该总是返回正确的HttpContext,但我在.asmx web-methods的EndExecuteMethod中看到它为null。 It would be great if somecan can confirm if I am right in making my last statement, but this statement is not the overall question I am trying to ask here. 如果有人可以确认我是否正确地做出我的最后陈述,那将是很好的,但这个陈述不是我在这里要问的整体问题。

After reading a good amount of literature (eg What is the difference between log4net.ThreadContext and log4net.LogicalThreadContext? , http://msmvps.com/blogs/jon_skeet/archive/2010/11/08/the-importance-of-context-and-a-question-of-explicitness.aspx , http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html and more including MSDN docs), here are my inferences: 在阅读了大量文献后(例如log4net.ThreadContext和log4net.LogicalThreadContext之间有什么区别?http: //msmvps.com/blogs/jon_skeet/archive/2010/11/08/the-importance-of-context -and-a-question-of-explicitness.aspxhttp://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html以及更多包括MSDN文档),以下是我的推论:

  1. ThreadStatic is local to underlying OS/.Net thread and not to the "logical" operation, hence in my example; ThreadStatic是底层OS / .Net线程的本地,而不是“逻辑”操作,因此在我的例子中; data set on first http request in "BeginExecute" would be visible in next http request if the second http request gets assigned the same thread as "BeginExecute" for first thread. 如果第二个http请求被分配了与第一个线程的“BeginExecute”相同的线程,则在“BeginExecute”中的第一个http请求中设置的数据将在下一个http请求中可见。 And this data won't be available in "EndExecute" if it happens to be re-assigned to another thread by .Net (which would happen in vast majority of the cases). 如果它恰好被.Net重新分配给另一个线程(在绝大多数情况下都会发生),那么这些数据将无法在“EndExecute”中获得。
  2. Thread.SetData is even more problematic for my use-case. 对于我的用例,Thread.SetData甚至更成问题。 It needs data slots to be passed in and if I were to pass in a data slot from a return value of Thread.GetNamedDataSlot, the information is available across the app domain; 它需要传入数据槽,如果我从Thread.GetNamedDataSlot的返回值传入数据槽,则该信息可在app域中获得; as named data slots are shared between threads. 由于命名数据​​槽在线程之间共享。
  3. CallContext.SetData is like ThreadStatic (which means its not shared by app domain but different http requests would see the same data if they get assgined to the same underlying OS/.Net thread). CallContext.SetData类似于ThreadStatic(这意味着它不被app域共享,但是如果它们被分配到相同的底层OS / .Net线程,则不同的http请求将看到相同的数据)。 CallContext.SetData provides an additional ability to marshal the context data for RPC calls which is irrelevant to the current question being asked. CallContext.SetData提供了一个额外的能力来编组RPC调用的上下文数据,这与当前提出的问题无关。
  4. Then there's the ThreadLocal class (.Net 4/.Net 4.5). 然后是ThreadLocal类(.Net 4 / .Net 4.5)。 It could have solved one part of my problem it seems, I could have passed it inside stateObject of BeingExecute operation, and extract from the same stateObject parameter of endExecute operation. 它本来可以解决我问题的一部分,我可以在BeingExecute操作的stateObject中传递它,并从endExecute操作的相同stateObject参数中提取。 From this perspective, ThreadLocal seems to be written for .Net's async support. 从这个角度来看,ThreadLocal似乎是为.Net的异步支持编写的。 But it won't work when I need to access it like HttpContext.Current as there's no way I can see to preserve the "logical thread static" instance ofit (unless I have said something incorrectly in my previous 3 points). 但是当我需要像HttpContext.Current那样访问它时它将无法工作,因为我无法看到保留“逻辑线程静态”实例(除非我在之前的3点中说错了)。
  5. And finally it seems CallContext.LogicalSetData does what I intend to achive. 最后似乎CallContext.LogicalSetData做了我打算实现的目标。 Using the set of CallContext.LogicalSetData and CallContext.LogicalGetData methods, I should be able to achieve the HttpContext.Current like impact which works correctly for "logical task executions". 使用CallContext.LogicalSetData和CallContext.LogicalGetData方法的集合,我应该能够实现HttpContext.Current这样的影响,它可以正常地用于“逻辑任务执行”。

Now come the questions: 现在来问题:

  1. Is everything I have said above correct. 我上面说的一切都是正确的。 Please correct any and all incorrect claims I have made. 请更正我所做的任何和所有不正确的声明。
  2. Are there any other options available for thread static kind of feature in .Net that I missed. 我错过了什么其他选项可用于.Net中的线程静态类型的功能。
  3. Does CallContext.LogicalSetData/LogicalGetData pass on the context data to RPC calls (the msdn page does not mention clearly, http://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.callcontext.logicalsetdata(v=vs.110).aspx ). CallContext.LogicalSetData / LogicalGetData是否将上下文数据传递给RPC调用(msdn页面没有明确提及, http://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.callcontext.logicalsetdata (v = vs.110).aspx )。
  4. Are there any downsides (performance wise or otherwise) of using CallContext.LogicalSetData/LogicalGetData. 使用CallContext.LogicalSetData / LogicalGetData是否有任何缺点(性能明智或其他方面)。
  5. This page says something about copy-on-write behavior for LogicalSetData: http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html . 本页介绍了LogicalSetData的写时复制行为: http//blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html In the context of async handlers/async MVC 5 action methods, what's the impact if I save a reference type using logicalsetdata and later change the state of the reference type. 在异步处理程序/异步MVC 5操作方法的上下文中,如果使用logicalsetdata保存引用类型并稍后更改引用类型的状态会产生什么影响。 What are the repuccursions. 什么是复发。
  6. For mutation/logicalsetdata/async, I still can't see what's the problem by mutating the object. 对于mutation / logicalsetdata / async,我仍然无法通过改变对象来看出问题是什么。 When the async method starts, the copy-on-write behavior would trigger a copy of context data the next time logicalsetdata is called. 当异步方法启动时,写入时复制行为将在下次调用logicalsetdata时触发上下文数据的副本。 This is a shallow copy, so my reference object is now actually shared by 2 logical contexts and the changes in one context are visible in the other context which is what I would normally expect from a reference type. 这是一个浅层副本,因此我的参考对象现在实际上由2个逻辑上下文共享,并且在另一个上下文中的更改在我通常期望的引用类型中是可见的。

A long question with lots of references, but hopefully I did my research well and the answers would benefit other people too. 一个很长的问题,有很多参考文献,但希望我做得很好,答案也会让其他人受益。

I am trying to figure out a way to set "logical thread" specific data that can be accessed consistently during a "logical" http request 我试图找出一种方法来设置“逻辑”特定数据,这些数据可以在“逻辑”http请求期间一致地访问

The only possible options are HttpContext.Current.Items and the logical CallContext . 唯一可能的选项是HttpContext.Current.Items和逻辑CallContext

Moreover, I am expecting that the data set in the "BeginExecute" part on whatever OS/.Net thread it was on is NOT available on a subsequent http request 此外,我期望在其上的任何OS / .Net线程的“BeginExecute”部分中设置的数据在随后的http请求中不可用

HttpContext.Current.Items will always be cleared on a new request, but you'll have to clear the logical CallContext data yourself. HttpContext.Current.Items将始终在新请求中清除,但您必须自己清除逻辑CallContext数据。

HttpContext.Current does not work correctly if you are using for example async .asmx web-service methods. 如果您使用的是异步.asmx Web服务方法,则HttpContext.Current无法正常工作。

I find this surprising. 我觉得这很令人惊讶。 I haven't tried it, but it should work - if you are running on .NET 4.5, targeting .NET 4.5 (ie, have targetFramework set to 4.5 in your web.config ), and aren't using async void . 我没有尝试过,但它应该工作 - 如果你在.NET 4.5上运行,目标是.NET 4.5(即,在web.config中将targetFramework设置为4.5 ),并且没有使用async void

[ThreadStatic] , thread-local data slots, (non-logical) CallContext , and ThreadLocal are all thread-specific data, and will not work for asynchronous code. [ThreadStatic] ,线程本地数据槽,(非逻辑) CallContextThreadLocal都是线程特定的数据,不适用于异步代码。

Is everything I have said above correct. 我上面说的一切都是正确的。 Please correct any and all incorrect claims I have made. 请更正我所做的任何和所有不正确的声明。

There is really way too much text in your question. 你的问题中有太多的文字。 Stack Overflow is a Q&A site, not a mentoring site. Stack Overflow是一个问答网站,而不是指导网站。

Are there any other options available for thread static kind of feature in .Net that I missed. 我错过了什么其他选项可用于.Net中的线程静态类型的功能。

No. 没有。

Does CallContext.LogicalSetData/LogicalGetData pass on the context data to RPC calls CallContext.LogicalSetData / LogicalGetData是否将上下文数据传递给RPC调用

I have no idea. 我不知道。 Try it and see. 试试看吧。

Are there any downsides (performance wise or otherwise) of using CallContext.LogicalSetData/LogicalGetData. 使用CallContext.LogicalSetData / LogicalGetData是否有任何缺点(性能明智或其他方面)。

There's a definite performance hit. 有明显的性能影响。 The .NET framework is highly optimized for the common case (no logical call context data). .NET框架针对常见情况(无逻辑调用上下文数据)进行了高度优化。

what's the impact if I save a reference type using logicalsetdata and later change the state of the reference type. 如果我使用logicalsetdata保存引用类型并稍后更改引用类型的状态会产生什么影响。

The logical CallContext has shallow-copy-on-write behavior. 逻辑CallContext具有浅拷贝写入行为。 So, any kind of asynchronous fork/join concurrency (ie, Task.WhenAll ) will end up sharing that state. 因此,任何类型的异步fork / join并发(即Task.WhenAll )最终都会共享该状态。 If you use ConfigureAwait(false) , you could also end up with race conditions. 如果您使用ConfigureAwait(false) ,您也可能最终遇到竞争条件。

To actually solve your problem, I recommend you first look into why HttpContext.Current doesn't work as expected; 为了真正解决您的问题,我建议您首先了解为什么HttpContext.Current不能按预期工作; my guess (without seeing the project) is that targetFramework is set to 4.0 instead of 4.5 . 我的猜测(没有看到项目)是targetFramework设置为4.0而不是4.5 HttpContext.Current.Items is the most performant choice if you can get it working. HttpContext.Current.Items是最高性能的选择,如果你可以让它工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM