代码之家  ›  专栏  ›  技术社区  ›  Jeff Meatball Yang

最小化事件日志记录对性能的影响?

  •  1
  • Jeff Meatball Yang  · 技术社区  · 14 年前

    我有一个静态日志函数,它使用StringBuilder在将字符串发送到日志之前连接一堆查询参数。这个进程可能会有相当长的时间,因为我们可能有~10个参数(.append调用),最后会有~200个字符长。

    我想最小化日志功能对性能的影响。(每个web请求可以多次调用这个日志功能,我们测量每个web请求的处理时间)

    如何/应该/可以建立一个stringbuilders“池”来提高性能?

    我也可以异步地完成所有这些日志记录,对吧?我该怎么做?

    5 回复  |  直到 12 年前
        1
  •  3
  •   Adam Robinson    14 年前

    由于日志记录通常依赖于状态,因此将日志条目的实际构造放到另一个线程中通常不是一个选项。但是,您可以捕获相关数据以异步格式化。虽然我不会在这里实现整个日志记录机制(尽管您可以看到 ProcessQueue article on CodeProject 为了更简单些),你可以这样做:

    public static void LogAsync<T1>(T1 value, Func<T1, string> formatter)
    {
        // asynchronously call formatter(value) and log the result
    }
    
    public static void LogAsync<T1, T2>(T1 value1, T2 value2, Func<T1, T2, string> formatter)
    {
        // asynchronously call formatter(value1, value2) and log the value
    }
    
    ...and so on
    

    如果字符串构造是导致日志记录停滞的原因,那么(假设 T 类型是不可变的,或者至少是 不要 呼叫之间的转换 LogAsync 什么时候 formatter 这应该会缓解这种情况。

        2
  •  4
  •   Eric J.    14 年前

    如果您预期日志记录活动会爆发,并且事件日志记录实际上会导致您已测量到的性能问题(请参阅 Premature Optimization 在“优化/设计级别”的“级别”下,您可以创建一个用于记录请求的队列和一个在队列之外工作的单独线程。如果调用方已满,则希望队列将其阻塞,直到未满为止。

    如果您的日志记录请求相当稳定,而不是突发性的活动,那么如果通常有一个cpu核心不在使用中,那么您仍然会获得总体收益。如果所有的CPU核心通常都在大量使用,那么单独的线程只会增加开销和复杂性,而不会带来好处。

        3
  •  2
  •   Chrish120    12 年前

    我强烈建议使用日志库,例如nlog。在这种情况下,它们具有高度的灵活性和性能,您还可以专注于业务逻辑。感谢你可能认为三党图书馆会很慢,但这不是我的经验,特别是与nlog。

    另一个选择是log4cpp,尽管这并不真正在开发中

        4
  •  1
  •   mfeingold    14 年前

    您可能需要的是应用程序正在处理的每个httprequest的stringbuilder实例。一个简单的方法是在global.asax中创建这个StringBuilder。

    您不必担心这个stringbuilder上的同步,因为在任何给定的时间,它都只能由一个httprequest访问。

    当请求处理完成时,您将不得不将StringBuilder的内容推送到某个中心位置(一个日志),在这里您将不得不担心同步问题,但是如果您将在OnedRequest事件中这样做,那么影响将是最小的。

    在将StringBuilder的内容移动到日志中之后,不要忘记清理它

        5
  •  1
  •   Guffa    14 年前

    不,不应将StringBuilder对象放在池中。它们的制造和使用都很便宜。如果你把它们放在一起,你只会把它们从短生命的物体变成长生命的物体。对于垃圾收集器来说,将一个stringbuilder迁移到下一代来保存它实际上比清理一大堆stringbuilder要复杂得多。

    架线工的使用绝对不会成为瓶颈。大部分的工作是将字符串存储在日志中,不管它在哪里。

    异步地进行日志记录本身不会节省任何性能。服务器仍然要做同样的工作,您只需增加创建另一个线程的开销。

    更有效的方法是保留一个要记录的字符串缓冲区,同时存储一堆字符串。当然,存储多个字符串实际上比存储一个和一个字符串更有效。

    您可以在静态变量中保留字符串列表,并在有足够的字符串时存储它们。(当然是同步访问,因为多个线程可以访问它)或者简单地从一个web请求中收集字符串并保存在一个web请求中,这要容易得多,但仍然可以节省一些工作。