首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >日志记录框架和多线程兼容性

日志记录框架和多线程兼容性
EN

Stack Overflow用户
提问于 2011-02-16 20:44:48
回答 1查看 2.3K关注 0票数 1

请注意,我在SO上看到了这些问题(讨论log4net的线程安全性),我怀疑它们回答了我的问题,但我还是要问:

多线程安全测井

Log4Net FileAppender不是线程安全吗?

最近,我编写了一个用于日志记录的WCF服务。这个想法非常类似于木塞 (或寻找钙下面的淤塞)。基本上,我已经实现了一个用于Silverlight客户机( Silverlight类库)的日志API。日志API或多或少是我们在应用程序其他地方使用的Common.Logging for .NET API的克隆。API的实现将所有日志消息转发给WCF日志服务,WCF日志服务本身是以Common.Logging实现的。

在查看阻塞时,我在Log4NetStrategy类中发现了下面的代码,让我觉得有些奇怪:

代码语言:javascript
复制
/// <summary> 
/// All Write log calls are done asynchronously because the DanielVaughan.Logging.Log 
/// uses the AppPool to dispatch calls to this method. Therefore we need to ensure 
/// that the call to Log is threadsafe. That is, if an appender such as FileAppender is used, 
/// then we need to ensure it is called from no more than one thread at a time. 
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="loggingEvent">The logging event.</param>
[MethodImpl(MethodImplOptions.Synchronized)]
static void WriteThreadSafe(ILogger logger, LoggingEvent loggingEvent)
{
  logger.Log(loggingEvent);
}

Log4NetStrategy (以及NLog和EnterpriseLibrary的策略)实现了一个接口,该接口有一个类似于写(ILogEntry logEntry)的方法。ILogEntry本质上是阻塞日志服务从客户端接收的DTO。提取来自logEntry的信息并用于创建log4net LoggingEvent。还根据log4net DTO中的记录器名称检索适当的ILogEntry记录器。在创建log4net LoggingEvent之后,它和记录器被发送到上面的WriteThreadSafe方法,并通过log4net进行记录。NLog和EnterpriesLibrary实现类似。

在伪代码中,阻塞日志服务上的“写”方法如下所示:

代码语言:javascript
复制
// Write on the logging service
// Send the input log entry to each configured strategy.
public void Write(ILogEntry logEntry)
{
  foreach (ILoggingStrategy ls in loggingStrategies)
  {
    ls.Write(logEntry);
  }
}

// Write on the Log4NetStrategy
// Convert the logEntry to log4net form and log with log4net
public void Write(ILogEntry logEntry)
{
  log4net.LoggingEvent le = ConvertToLoggingEvent(logEntry);
  ILog logger = log4net.GetLogger(logEntry.Logger);
  WriteThreadSafe(logger, le);
}

所以我的问题是..。通常,log4net (和NLog,我假设是EnterpriseLibrary)被认为是多线程兼容的。也就是说,公共API的用户可以简单地调用log.Info、log.Log等,而不关心在多线程环境中运行。日志框架应该确保日志记录调用(以及日志调用中的任何处理)都是线程安全。

如果日志记录框架与多线程兼容,则使用

代码语言:javascript
复制
[MethodImpl(MethodImplOptions.Synchronized]

属性真的需要吗?这似乎只会(或可能)导致瓶颈,强迫同步处理所有日志记录消息,即使底层日志框架应该能够在多线程环境中处理日志记录。

在我的日志记录服务(它可以是多线程)的情况下,似乎没有必要像这样同步调用。看起来,我应该能够从服务调用中获取日志输入,构建适当的日志结构(基于底层日志框架),并将其记录下来。如果我的日志记录服务是多线程的,它应该“只工作”,因为底层日志记录框架应该支持它(多线程)。

这有道理吗?是否真的需要显式同步日志记录调用(至少对于log4net和NLog是这样)?

EN

回答 1

Stack Overflow用户

发布于 2011-02-16 22:09:08

为什么是锁?

据我所知,在企业库中,使用.NET Tracelistener类,它有一个属性IsThreadSafe。如果侦听器是线程安全的,则不执行同步。对于作为输出设备的文件,没有理由同步来自多个线程的访问,除非内部保存写缓冲区的StreamWriter可能因不同步写入而损坏。这就是为什么您需要获得一个同步StreamWriter来从不同的线程写入一个文件。

但无论如何,这更有学术意义。当一次只允许一个线程写入时,仍然可以生成几百MB的输出,这甚至会导致最快的硬盘崩溃。写入文件时,您是IO绑定的。整个链中最慢的是硬盘,而不是同步写入文件。但是有时在一个文件中有几个进程的输出是很好的。例如,Log4Net 不可能就这样做了。

..。如何使多个进程登录到同一个文件? FileAppender在日志记录时对日志文件持有写锁。这将防止其他进程写入文件,因此不可能让多个进程直接日志到同一个日志文件,即使它们位于同一台计算机上。..。

格式化性能

即使你认为锁在浪费你的性能,也经常会有其他的成本被忽视。可配置的输出格式非常好,但至少在4.0之前的企业库中的格式是很慢。我使它的速度快了13倍以上,这导致了一个因子2的净文件吞吐量增加。

并发写入文件

有了一点Win32魔力,可能就可以从不同的进程并发地将可靠的代码写入同一个文件。但是回到您的问题是否需要同步:它可能是需要的,取决于输出设备。

规整性

如果您的关注点是可伸缩性,那么您需要有一个每个线程缓冲区,该缓冲区在定义的时间点被合并,以允许快速的数据收集。然后,您可以实现一个全局环缓冲区,它从所有线程获取格式化数据,其中最老的数据被覆盖。当发生有趣的事情时,您可以将整个环形缓冲区转储到磁盘上。这种设计比任何文件附录都快10-20倍。Windows事件跟踪确实使用了速度惊人的环形缓冲技巧。

既然您问到了锁定的问题,我确实认为速度是您的主要关注点。如果这个假设是正确的,那么您应该看看追踪框架,就像ApiChange工具使用的那种。它有一些创新的方法,比如当您的方法被留下一个异常时自动跟踪异常,或者在不需要修改产品代码的情况下对错误路径进行单元测试。

为了具有可伸缩性,您应该区分日志记录和跟踪,就像我在这里解释的:日志记录不是跟踪。

无锁

如果您想要创建一个可伸缩的跟踪框架,您需要将一个跟踪调用的所有数据作为不可变数据传递,将数据格式化为一个字符串并将其传递给您的输出设备。它可以简单如(C#伪码)

  1. Trace.Info("blahh {0}",data);
  2. traceString =格式(formatString,args,CurrentTime);
  3. 写(TraceString);

当数据未存储在类中或类成员在初始化后不更改时,您将不需要锁。您必须小心,这样才能在线程之间共享格式缓冲区。要具有可伸缩性,您需要按照以下顺序设置线程安全的设计优先级。

  1. 隔离--这是目前为止最好的解决方案。如果问题可以被分割成几个线程可以独立操作的方式,那么您就不需要考虑锁定或共享数据。
  2. Immutability第二个最好的解决方案是共享数据,但是如果不止一个线程可以“看到”它,那么它就永远不能改变。这可以实现,例如,对象只有getter,并且所有数据都通过ctor传递。
  3. 锁定--如果使用无锁或某些锁定策略--无关紧要。在痛苦的世界里,你必须注意处理器缓存,虚假共享,如果你勇敢的话,你甚至尝试一些没有锁的方法,结果发现它充其量是普通锁的两倍。在某些情况下,锁空闲代码可能会慢一些。

如果您想了解更多关于线程的详细信息,我建议使用博客

追踪策略

要编写可维护的软件,您需要能够跟踪应用程序和数据流。只有这样,你才能诊断问题,这些问题只发生在你的客户网站。如果你的代码被跟踪“乱七八糟”,这确实会给你提供足够的信息,让你快速解决diagnos的问题。您可以跟踪太多、太少或不相关的数据。一条很好的跟踪行(例如,您的XPath查询字符串与它所操作的文件相关)作为日志文件中分散的信息要好得多。

你的,Alois Kraus

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5021892

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档