[转]C# 超高速高性能写日志 代码开源
1、需求
需求很简单,就是在C#开发中高速写日志。比如在高并发,高流量的地方需要写日志。我们知道程序在操作磁盘时是比较耗时的,所以我们把日志写到磁盘上会有一定的时间耗在上面,这些并不是我们想看到的。
2、解决方案
2.1、简单原理说明
使用列队先缓存到内存,然后我们一直有个线程再从列队中写到磁盘上,这样就可以高速高性能的写日志了。因为速度慢的地方我们分离出来了,也就是说程序在把日志扔给列队后,程序的日志部分就算完成了,后面操作磁盘耗时的部分程序是不需要关心的,由另一个线程操作。
俗话说,鱼和熊掌不可兼得,这样会有一个问题,就是如果日志已经到列队了这个时候程序崩溃或者电脑断电都会导致日志部分丢失,但是有些地方为了高性能的写日志,是否可以忽略一些情况,请各位根据情况而定。
2.2、示例图

3、关键代码部分
这里写日志的部分LZ选用了比较常用的log4net,当然也可以选择其他的日志组件,比如nlog等等。
3.1、日志至列队部分
第一步我们首先需要把日志放到列队中,然后才能从列队中写到磁盘上。

public void EnqueueMessage(string message, FlashLogLevel level, Exception ex = null)
{
if ((level == FlashLogLevel.Debug && _log.IsDebugEnabled)
|| (level == FlashLogLevel.Error && _log.IsErrorEnabled)
|| (level == FlashLogLevel.Fatal && _log.IsFatalEnabled)
|| (level == FlashLogLevel.Info && _log.IsInfoEnabled)
|| (level == FlashLogLevel.Warn && _log.IsWarnEnabled))
{
_que.Enqueue(new FlashLogMessage
{
Message = "[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff") + "]\r\n" + message,
Level = level,
Exception = ex
}); // 通知线程往磁盘中写日志
_mre.Set();
}
}

_log是log4net日志组件的ILog,其中包含了写日志,判断日志等级等功能,代码开始部分的if判断就是判断等级和现在的日志等级做对比,看是否需要写入列队,这样可以有效的提高日志的性能。
其中的_que是ConcurrentQueue列队。_mre是ManualResetEvent信号,ManualResetEvent是用来通知线程列队中有新的日志,可以从列队中写入磁盘了。当从列队中写完日志后,重新设置信号,在等待下次有新的日志到来。
3.2、列队到磁盘
从列队到磁盘我们需要有一个线程从列队写入磁盘,也就是说我们在程序启动时就要加载这个线程,比如asp.net中就要在global中的Application_Start中加载。

/// <summary>
/// 另一个线程记录日志,只在程序初始化时调用一次
/// </summary>
public void Register()
{
Thread t = new Thread(new ThreadStart(WriteLog));
t.IsBackground = false;
t.Start();
} /// <summary>
/// 从队列中写日志至磁盘
/// </summary>
private void WriteLog()
{
while (true)
{
// 等待信号通知
_mre.WaitOne(); FlashLogMessage msg;
// 判断是否有内容需要如磁盘 从列队中获取内容,并删除列队中的内容
while (_que.Count > 0 && _que.TryDequeue(out msg))
{
// 判断日志等级,然后写日志
switch (msg.Level)
{
case FlashLogLevel.Debug:
_log.Debug(msg.Message, msg.Exception);
break;
case FlashLogLevel.Info:
_log.Info(msg.Message, msg.Exception);
break;
case FlashLogLevel.Error:
_log.Error(msg.Message, msg.Exception);
break;
case FlashLogLevel.Warn:
_log.Warn(msg.Message, msg.Exception);
break;
case FlashLogLevel.Fatal:
_log.Fatal(msg.Message, msg.Exception);
break;
}
} // 重新设置信号
_mre.Reset();
}
}

3.3、完整代码
4、性能对比和应用
4.1、性能对比
经过测试发现
使用原始的log4net写入日志100000条数据需要:19104毫秒。
同样数据使用列队方式只需要251毫秒。

4.2、应用
4.2.1、需要在程序启动时注册,如asp.net 程序中在Global.asax中的Application_Start注册。

public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles); FlashLogger.Instance().Register();
}
}

4.2.2、在需要写入日志的地方直接调用FlashLogger的静态方法即可。
FlashLogger.Debug("Debug");
FlashLogger.Debug("Debug", new Exception("testexception"));
FlashLogger.Info("Info");
FlashLogger.Fatal("Fatal");
FlashLogger.Error("Error");
FlashLogger.Warn("Warn", new Exception("testexception"));
5、代码开源
https://github.com/Emrys5/Emrys.FlashLog
转自 http://www.cnblogs.com/emrys5/p/flashlog.html
[转]C# 超高速高性能写日志 代码开源的更多相关文章
- C# 超高速高性能写日志 代码开源
1.需求 需求很简单,就是在C#开发中高速写日志.比如在高并发,高流量的地方需要写日志.我们知道程序在操作磁盘时是比较耗时的,所以我们把日志写到磁盘上会有一定的时间耗在上面,这些并不是我们想看到的. ...
- JAVA语言之怎样写出高性能的Java代码?
本文主要向大家介绍了JAVA语言之怎样写出高性能的 Java 代码?通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. 在这篇文章中,我们将讨论几个有助于提升Java应用程序性能的方法.我 ...
- 收藏收藏:时隔一年,你关注的打造一个实用的TXT文本操作及日志框架,我们开源了,不再为程序写日志发愁(也支持.net core哦)
记得做这个框架是在2018年刚接触.net core的时候,那个时候为了能够专心的研究我开始不写博客了,但是学有所成并在公司运用了近一年的时间了,决定回来和各位分享我们所掌握的那星星点点的知识,希望可 ...
- 2.2 代码块--delphi 写日志模块
//2.2 代码块--写日志 //调用例句如:LogMsg('FTP上传线程终止',False,true); procedure LogMsg(AMsg: string; const blnIsErr ...
- How To Write In Sharepoint Log File 怎么对自定义的MOSS代码写日志
How To Write In Sharepoint Log File 怎么对自定义的MOSS代码写日志 Add Microsoft.Office.Server dll in your project ...
- 【编程练习】收集的一些c++代码片,算法排序,读文件,写日志,快速求积分等等
写日志: class LogFile { public: static LogFile &instance(); operator FILE *() const { return m_file ...
- 之前写的收集的一些c++代码片,算法排序,读文件,写日志,快速求积分等等
写日志: class LogFile { public: static LogFile &instance(); operator FILE *() const { return m_file ...
- 重复造轮子,编写一个轻量级的异步写日志的实用工具类(LogAsyncWriter)
一说到写日志,大家可能推荐一堆的开源日志框架,如:Log4Net.NLog,这些日志框架确实也不错,比较强大也比较灵活,但也正因为又强大又灵活,导致我们使用他们时需要引用一些DLL,同时还要学习各种用 ...
- .NET Core的日志[5]:利用TraceSource写日志
从微软推出第一个版本的.NET Framework的时候,就在“System.Diagnostics”命名空间中提供了Debug和Trace两个类帮助我们完成针对调试和跟踪信息的日志记录.在.NET ...
随机推荐
- udp套接字使用信号驱动式I/O
信号驱动式I/O的本质就是:进程预先告知内核当某个描写叙述符发生事件时,内核会向该进程发送SIGIO信号通知进程,进程可在信号处理函数中进行处理 进程能够通过fcntl打开O_ASYNC标志或ioct ...
- 逻辑回归的相关问题及java实现
本讲主要说下逻辑回归的相关问题和详细的实现方法 1. 什么是逻辑回归 逻辑回归是线性回归的一种,那么什么是回归,什么是线性回归 回归指的是公式已知,对公式中的未知參数进行预计,注意公式必须是已知的,否 ...
- 【C++】排序算法小结
1.计数排序 如果给定上下界,并且区间不大的话,最适用. 比如对于英文字母数组进行排序. 时间复杂度O(n),空间复杂度O(n) void countSort(int A[], int n, int ...
- EF性能
批量操作时,加上这句:Context.Configuration.AutoDetectChangesEnabled = false; 主要是取消跟踪,缩短对象添加到上下文的时间(非执行SQL的时间)
- create table like 和create table select 比较
语法: CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)] [table_optio ...
- atitit.研发管理--标准化流程总结---java开发环境与项目部署环境的搭建工具包总结
atitit.研发管理--标准化流程总结---java开发环境与项目部署环境的搭建工具包总结 1. ide系列(只开发环境需要,但部署环境也做好放上,很有用) 1 2. web服务器+sdk+网站程序 ...
- Python 元祖的操作
注意:元祖定义后不可修改,单个元祖后面必须加逗号,否则认为是字符串:tuple = ('apple',) 1.定义元祖 tuple = ('apple','banana','grape','orang ...
- zepto与jquery冲突
公司项目中一直用的都是zepto,但是jQuery扩展的插件比较多. jQuery有一个方法noConflict(),可以把jQuery的$改掉.var aa = $.noConflict();就用a ...
- WP8持续集成之通过命令行跑单元测试
理论基础 对于如何在WP8上创建单元测试工程,在这里首先提供一个MSDN的文档作为参考. http://msdn.microsoft.com/en-us/library/windowsphon ...
- Hadoop中MapReduce计算框架以及HDFS可以干点啥
我准备学习用hadoop来实现下面的过程: 词频统计 存储海量的视频数据 倒排索引 数据去重 数据排序 聚类分析 ============= 先写这么多