如何有效异步日志? [英] How to effectively log asynchronously?

查看:206
本文介绍了如何有效异步日志?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对我的一个项目使用企业库4用于记录(和其他目的)。我注意到,有一些代价,我这样做,我可以做记录在一个单独的线程缓解记录。

I am using Enterprise Library 4 on one of my projects for logging (and other purposes). I've noticed that there is some cost to the logging that I am doing that I can mitigate by doing the logging on a separate thread.

我现在这样做的方式是创建一个LogEntry对象,然后我调用BeginInvoke的调用Logger.Write的委托。

The way I am doing this now is that I create a LogEntry object and then I call BeginInvoke on a delegate that calls Logger.Write.

new Action<LogEntry>(Logger.Write).BeginInvoke(le, null, null);

我真正想要做的是添加日志消息队列,然后有一个单独的线程拉LogEntry情况下,从队列和执行日志操作。这样做的好处是,日志记录不与执行操作的冲突,而不是在工作的每个日志操作结果的线程池抛出越来越

What I'd really like to do is add the log message to a queue and then have a single thread pulling LogEntry instances off the queue and performing the log operation. The benefit of this would be that logging is not interfering with the executing operation and not every logging operation results in a job getting thrown on the thread pool.

我怎样才能创建一个支持许多作家和一位读者在一个线程安全的方式共享队列?被设计为支持许多作家(而不会导致同步/阻塞)队列执行和一个单一的阅读器的一些例子将是非常美联社preciated。

How can I create a shared queue that supports many writers and one reader in a thread safe way? Some examples of a queue implementation that is designed to support many writers (without causing synchronization/blocking) and a single reader would be really appreciated.

关于建议的替代方法也将是AP preciated,我不感兴趣,虽然改变日志框架。

Recommendation regarding alternative approaches would also be appreciated, I am not interested in changing logging frameworks though.

推荐答案

我写这篇code而回,感觉自由地使用它。

I wrote this code a while back, feel free to use it.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace MediaBrowser.Library.Logging {
    public abstract class ThreadedLogger : LoggerBase {

        Queue<Action> queue = new Queue<Action>();
        AutoResetEvent hasNewItems = new AutoResetEvent(false);
        volatile bool waiting = false;

        public ThreadedLogger() : base() {
            Thread loggingThread = new Thread(new ThreadStart(ProcessQueue));
            loggingThread.IsBackground = true;
            loggingThread.Start();
        }


        void ProcessQueue() {
            while (true) {
                waiting = true;
                hasNewItems.WaitOne(10000,true);
                waiting = false;

                Queue<Action> queueCopy;
                lock (queue) {
                    queueCopy = new Queue<Action>(queue);
                    queue.Clear();
                }

                foreach (var log in queueCopy) {
                    log();
                }
            }
        }

        public override void LogMessage(LogRow row) {
            lock (queue) {
                queue.Enqueue(() => AsyncLogMessage(row));
            }
            hasNewItems.Set();
        }

        protected abstract void AsyncLogMessage(LogRow row);


        public override void Flush() {
            while (!waiting) {
                Thread.Sleep(1);
            }
        }
    }
}

一些优点:


  • 它让后台记录活着,所以它不需要旋转向上和自旋向下线程。

  • 它使用一个单一的线程服务队列中,这意味着绝不会有其中100线程服务队列的情况。

  • 它复制队列,确保队列在执行日志的操作不会被阻止

  • 它使用的AutoResetEvent,以确保BG线程处于等待状态

  • 这是,恕我直言,很容易遵循

下面是一个稍微改进过的版本,记住我对其执行非常少的测试,但它确实解决了一些小问题。

Here is a slightly improved version, keep in mind I performed very little testing on it, but it does address a few minor issues.

public abstract class ThreadedLogger : IDisposable {

    Queue<Action> queue = new Queue<Action>();
    ManualResetEvent hasNewItems = new ManualResetEvent(false);
    ManualResetEvent terminate = new ManualResetEvent(false);
    ManualResetEvent waiting = new ManualResetEvent(false);

    Thread loggingThread; 

    public ThreadedLogger() {
        loggingThread = new Thread(new ThreadStart(ProcessQueue));
        loggingThread.IsBackground = true;
        // this is performed from a bg thread, to ensure the queue is serviced from a single thread
        loggingThread.Start();
    }


    void ProcessQueue() {
        while (true) {
            waiting.Set();
            int i = ManualResetEvent.WaitAny(new WaitHandle[] { hasNewItems, terminate });
            // terminate was signaled 
            if (i == 1) return; 
            hasNewItems.Reset();
            waiting.Reset();

            Queue<Action> queueCopy;
            lock (queue) {
                queueCopy = new Queue<Action>(queue);
                queue.Clear();
            }

            foreach (var log in queueCopy) {
                log();
            }    
        }
    }

    public void LogMessage(LogRow row) {
        lock (queue) {
            queue.Enqueue(() => AsyncLogMessage(row));
        }
        hasNewItems.Set();
    }

    protected abstract void AsyncLogMessage(LogRow row);


    public void Flush() {
        waiting.WaitOne();
    }


    public void Dispose() {
        terminate.Set();
        loggingThread.Join();
    }
}

在原有优势:


  • 这是一次性的,这样你就可以摆脱异步记录器

  • 冲洗语义改进

  • 它将回应略好于一阵接着沉默

这篇关于如何有效异步日志?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆