log4net.ThreadContext和log4net.LogicalThreadContext有什么区别?

28

更新于2014年11月18日——在浏览log4net源代码库时,我发现LogicalThreadContext的实现已于2011年11月进行修改,使用CallContext.LogicalSetData(并使用LogicalGetData获取)存储其属性。这很重要,因为这意味着LogicalThreadContext现在应该能够正常工作。存储在LogicalThreadContext中的任何数据都应该“流动”到任何子线程或任务中。与ThreadContext(和LogicalThreadContext的旧实现)相比,存储在上下文中的数据将仅保留在当前线程中,而不会传递到子线程/任务。

如果您感兴趣,可以查看以下更改:

http://svn.apache.org/viewvc/logging/log4net/trunk/src/log4net/Util/LogicalThreadContextProperties.cs?r1=1165341&r2=1207948&diff_format=h

希望偶然发现这个旧问题的人会发现这些信息很有用。 log4net提供了两种不同的“线程上下文”对象:ThreadContextLogicalThreadContext,每个对象都有一个属性包,即Properties。ThreadContext具有ThreadContextProperties包,而LogicalThreadContext具有LogicalThreadContextProperties包。
ThreadContext可能更常被称为“MDC”。 LogicalContext可能更常被称为“LDC”。 本文中将使用简称。
MDC.Properties使用System.Threading.Thread.SetData实现,而LDC.Properties使用System.Runtime.Remoting.Messaging.CallContext.SetData实现。
相比之下,NLog只公开“MDC”(现在称为MappedDiagnosticContext)以存储线程本地属性。 NLog的实现使用System.Threading.Thread.SetData,因此其实现与log4net的实现相同。
在log4net和NLog中,“MDC”属性都存储在字典中,该字典本身存储在线程本地存储中。
在这种情况下,将字典存储在带有[ThreadStatic]修饰的类成员变量中是否等效?
[ThreadStatic]
private static IDictionary<string, string> threadProperties;

使用.NET 4.0的新ThreadLocal类,有什么等效(或相似)的声明?

最终,LDC和MDC之间的实际差异是什么?即使阅读了上面链接的MSDN主题,我仍然不清楚。你什么情况下会真正使用其中的一个而不是另一个?似乎我看到的大多数关于log4net和context的参考/示例都是GDC(全局-我理解的),NDC(嵌套-我也理解的)和MDC。在谷歌搜索时,我能找到的与LDC(或LogicalThreadContext)相关的大多数参考资料都与提交到log4net源代码存储库有关,而不是真实世界的用法。 LDC几乎从不在问题或示例中提到。

我找到了this链接,它提供了一些来自log4net开发人员Nicko Cadell的很好的信息,但对我来说仍然不清楚。

一个更大的问题,与log4net无直接关系,那就是Thread.SetData和CallContext.SetData之间的实际区别是什么?

根据CallContext MSDN文章,CallContext数据可以传播到另一个AppDomain。为了传播,存储在CallContext中的数据项必须公开ILogicalThreadAffinative接口。所以,这似乎是Thread.SetData和CallContext之间的一个区别。
根据Nicko Cadell的链接,log4net没有实现ILogicalThreadAffinative,因此LDC属性将不会被传播。
也许这里有足够的信息让我能回答自己的问题,也可能不行。我仍在努力理解。
如果您使用log4net,您是否使用MDC,LDC或两者都使用?如果您使用MDC,是因为大多数“现实世界”的示例似乎使用它吗?如果您使用LDC,则使用它的特定原因是什么?如果您同时使用两者,您如何选择何时使用哪个?
请注意,我看过一些关于MDC(以及可能是LDC)在ASP.net应用程序中由于线程切换而可能无法正常工作的文章。我对此问题并不特别感兴趣,因为我没有在ASP.net上工作。
实际上,我在SO上找到了几篇有用的帖子,可能有助于讨论: What are best practices for using thread local storage in .NET?

.Net:逻辑线程和线程本地存储?

提前致谢!

1个回答

8

警告:这只是猜测。

假设您正在编写一个服务器,并且服务请求意味着您必须与许多不同的服务进行通信。作为一名彻底现代化的开发人员,您会异步地进行这些请求,协调所有回复(或超时),以便响应原始请求。

这意味着与单个请求对应的工作分散在许多不同的线程中(异步处理Web服务响应)。我怀疑使用CallContext将“我正在做的一切都是因为这个传入请求”传播到不同的线程,以便您可以将该请求的所有日志聚集在一起。 ThreadContext 在这里无法帮助。请注意,我假设所有工作都在单个AppDomain中执行,因此您的担忧不会成为问题。


实际上这似乎并不是这样,我的当前经验与 .net 4.5 web api 和异步请求是,CallContext 并没有被传递,而仅限于该线程的调用。我在 StackOverflow 回答了一个问题,并提供了一些详细信息,导致我来到这里:http://stackoverflow.com/questions/4507968/whats-the-difference-between-log4net-threadlogicalcontext-and-log4net-threadcon - Tommy G.
@TommyG:第三次尝试发表这个评论 :) 看起来有多种因素在起作用,它们取决于框架的版本和log4net的版本。请参见https://dev59.com/v2kw5IYBdhLWcg3wlroa -听起来CallContext 应该可以工作,但是log4net中存在(或曾经存在)一个bug,阻止了LogicalThreadContext与其良好协同工作。 - Jon Skeet
嗨,Jon,从我阅读它的角度来看,这也是我对LogicalThreadContext的理解,但是感谢你分享其他问题,那是很好的信息。 - Tommy G.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接