【问题标题】:Can I get measurable speed improvements by replacing Console.WriteLine with a logging framework?我可以通过用日志框架替换 Console.WriteLine 来获得可衡量的速度改进吗?
【发布时间】:2012-03-01 21:34:17
【问题描述】:

目前,我们的 C#、.Net 3.5 win 应用程序做了很多 Console.WriteLine() 来保留“软”日志(不保存在文件中),这既不完全有用,也可能有点性能瓶颈,尤其是因为它的目的是尽可能快地进行一堆计算。

我刚加入团队,所以我没有时间分析平均运行时间,但在我看来,必须通过将控制台输出替换为以下内容来改进

  • 针对速度进行了优化
  • 可在运行时配置,即可开启和关闭

配置很棒,但我不知道通过框架(Log4Net 或其他)切换到同等数量的日志记录是否会提高或降低性能。

我的直觉告诉我,在 Log4Net 中将相同的日志记录到相同的输出可能会稍微慢一些,因为它本质上是在做同样的事情,但必须通过另一个库。这是正确的还是需要一些捷径来加快速度?

我还认为跳过控制台并直接写入日志文件会更快(没有缓冲区刷新等),并且可以保存以供审查/审计/后代使用 - 因此总体而言是最佳选择。

我的想法有意义吗?我可以自信地向团队领导提出建议吗?当然,我可以可靠地测试它的唯一方法是实现它,但我希望我可以用其他人的知识和经验来支持我最初的建议。

【问题讨论】:

  • 控制台非常慢。专为人眼而不是记录器而设计。所以是的,轻松获胜。
  • 可能是一个瓶颈?如果您担心性能,您应该做的第一件事是配置文件,而不是猜测可能会慢。
  • @svick 这是非常正确的。但是重复和不必要的控制台 I/O 是导致速度变慢的一个很好的候选,你不觉得吗?
  • @Alex,我的想法并不重要。唯一重要的是您的分析器所说的内容。我认为试图避免不必要的控制台 IO 很可能是过早的优化。
  • @svick 我会记住这个陷阱,先做一些分析,谢谢。

标签: .net performance logging


【解决方案1】:

我不愿回答,因为你自己已经给出了我的答案,但我很想得到代表 :) ...

根据我的经验,控制台日志记录是所有选项中最慢的选项。我经常从控制台日志开始,当我关闭它时,我总是惊讶于程序运行的速度有多快。我认为,当您登录控制台时,您甚至不会注意到某些中间框架的(小)开销。

我通常发现写入文件并使用专用的日志查看器软件观看它要快得多(抱歉,我手头没有任何软件名称,但谷歌应该会帮你找到软件)。

还有一个选项可以使用,例如。 OutputDebugString 和查看实用程序(抱歉,再次,没有名称),如果您想在运行时查看日志。

当然,为运行后分析保存日志文件是一件好事,在开始使用后您可能不会再错过它。

增强的可配置性当然是一个好处,除了全局打开和关闭登录之外,我个人并没有太多使用它(好吧,有时,如果我希望一些消息也出现在生产中,我会使用两三个不同的跟踪级别代码)。

所以我认为,你的胆量是对的,我建议尽快切换到一些框架:)

只有一句话:

没有缓冲区刷新等

我强烈建议,不要禁用缓冲区刷新。我在每条消息后刷新我的日志缓冲区。在程序崩溃的情况下,如果您丢失了崩溃前的最后一条消息,您将不知道出了什么问题。

【讨论】:

  • 这太好了,我在正确的轨道上松了一口气:) 实际上同意缓冲区刷新,我不希望看到整个运行日志消失,因为我想跳过几毫秒。不过,实际上并不知道 Log4Net 默认会做什么。
  • TextWriterAppender.ImmediateFlush 的 API 信息(FileAppender 从中继承)说,默认设置是在每次追加后刷新(一个明智的决定:) ...)。见这里:logging.apache.org/log4net/release/sdk/…
  • 布里尔,谢谢。 “确实,当跳过刷新时,很可能在应用程序退出时最后几个日志事件不会记录在磁盘上。即使获得 20% 的性能提升,这也是一个高昂的代价。”是啊,我想我会继续冲洗!
  • “总是刷新你的日志”这句话突然出现在我的脑海中,现在我忍不住咯咯地笑了。
【解决方案2】:

基本上,我同意@Martin,但想一想。 每秒记录多少条消息?

如果它有数百个或更多,那么摆脱对控制台的写入可能会节省大量时间。

如果你想加快速度,你总是需要考虑某事花费了多少时间

【讨论】:

  • 这很好。我不确定记录日志花费了多少时间——正如我所说的,我是团队的新成员。但如果我能节省 5-10% 的时间,那么简单地换成 log4net 可能是值得的。必须按照@svick 的建议进行一些分析。
  • @Alex:你可以在有或没有控制台的情况下计时。 (我对分析器的看法很模糊;-)
  • 我实际上对所有控制台内容进行了全局注释,并将运行时间减少了 25%。我可能仍然需要至少一些日志记录,所以它不会有如此巨大的收益,但仍然是一个好的开始:)
【解决方案3】:

我只是要添加一个简短的示例,因为我们遇到了非常相似的问题,并且可能会对此信息感兴趣。

在我们的应用程序中,我们大量使用了 Log4Net。通过分析应用程序,我们意识到 ILog.Log 方法花费了过多的时间。本质上,每个 Logging 调用都是一个阻塞调用,它将一行写入文本文件。配置中的一个简单更改,将RollingFileAppender 替换为自定义BufferedFileAppender,显着提高了我们应用程序的性能。令人难以置信的是,一些涉及大量日志记录且以前需要几秒钟的操作在进行此切换后下降到亚秒级。

BufferedFileAppender 本质上是通过对日志消息进行排队和执行更少的文件写入来一次批处理许多日志消息。这确保 ILog.Log 的行为类似于异步调用(就性能而言),但也确保日志消息的确定性有序处理。

我会想象在您的情况下 Console.WriteLine 会阻塞-理想情况下,您需要做的是批处理操作并一次写入 100 行(或者说每 100 毫秒写入已缓冲的任何行)。可以编写一个围绕 Console.WriteLine 的简单包装类来实现这一点。

【讨论】:

  • 理想情况下,是的——刚刚看到 Log4Net 提供了一个 BufferingAppenderSkeleton,看起来很有用。我想这将取决于再次分析,但我一定会记住这一点。
  • 仅供参考,通过自己编写,您可以实现一个不错的队列和异步写入,然后一个单独的线程从队列中获取数据以写入文件。这将使您在性能和尽快写入日志之间取得良好的平衡,以便在发生崩溃时获取消息。
猜你喜欢
  • 1970-01-01
  • 2013-11-12
  • 2023-03-15
  • 1970-01-01
  • 2021-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多