【问题标题】:Profling performance of custom logger class, for an application reading Word document自定义记录器类的性能分析,用于读取 Word 文档的应用程序
【发布时间】:2020-02-04 22:14:47
【问题描述】:

我有一个应用程序,它使用OpenXmlPowerTools 从 .docx 文件中读取 cmets 和段落。它是一个控制台应用程序,它在运行时会创建一个 debug.log 文件。

实现了一个记录器类,它将消息保存到所有构建的文本文件中,并将这些消息打印到控制台以进行调试构建。以下代码是该记录器类的一部分:

public static class Logger
{
    public enum LogLevel
    {
        ERROR, WARNING, DEBUG
    }

    public static void Log(string message, LogLevel level, bool newline)
    {
        try
        {
            // the very next line was a hotspot, as shown in the profiler
            using (StreamWriter sw = File.AppendText(path))
            {
                // write the messages to this file
            }
        }
        catch (Exception ex)
        {
            // handle it
            // I know it is bad practice to catch System.Exception, I need to fix this.
        }
     }
}

在代码中,这个函数经常被这样调用:

private void doSomething(string someParameter)
{
    Logger.Log("The parameter is: " + someParameter, Logger.LogLevel.DEBUG, true);
}

我已经分析了它的性能,对于一个包含几十个 cmets 的相当大的 word 文档,它需要 1 分 40 秒才能完成。没有记录,只需要几秒钟。经过一番调查,似乎File.AppendText 在.NET 中非常慢。

作为替代方案,我尝试使用缓冲区:

using (StreamWriter sw = new StreamWriter(path, false, Encoding.UTF8, 65536)
{
    // write the messages to the file
}

与我读过的推荐这种方法的文章中的信息相反,性能似乎变差了(耗时超过 2 分钟)。为什么是这样?我怎样才能提高它的性能?

【问题讨论】:

    标签: c# .net file logging streamwriter


    【解决方案1】:

    您的日志记录代码错误。这就是 Entprise Library 15 年前开始的方式,但结果并不好。 使用日志框架并完成它。

    现在讨论您的实际问题。您为每个日志调用打开和关闭文件,这非常慢并且会导致大量开销。保持 Log 文件和 StreamWriter 处于打开状态并使用锁来确保不会将数据并发写入日志文件。 接下来,您需要处理生命周期问题,因为如果首先完成 FileStream,您的 StreamWriter 将无法将挂起的数据刷新到磁盘,并且您会丢失最后的日志消息(很可能是具有崩溃异常消息的重要消息)。

    要解决在每个日志上刷新的问题,请调用 StreamWriter(慢)或创建一个派生自 CriticalFinalizerObject 并保持 FileStream 打开并在 FileStream 实例上调用 GC.SuppressFinalize 的包装类,以防止在应用程序关闭期间提前完成。

    这是您在创建自己的日志库时会遇到的最常见的陷阱。

    小型记录器是例如这里: https://github.com/Alois-xx/WMIWatcher/blob/master/FileLogger.cs

    【讨论】:

    • 您的意思是将整个代码包装在using 块中吗?我对锁不熟悉。您能否提供一些示例代码来说明您的意思,或者指出一些我可以阅读的资源来帮助解决这个问题?
    • 我添加了一个小型记录器示例,它完成了大部分工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-10
    • 1970-01-01
    • 1970-01-01
    • 2011-03-03
    • 1970-01-01
    • 1970-01-01
    • 2021-11-23
    相关资源
    最近更新 更多