HTML5技术

性能秒杀log4net的NLogger日志组件(附测试代码与NLogger源码) - Sam Xiao

字号+ 作者:H5之家 来源:H5之家 2017-02-13 17:00 我要评论( )

NLogger特点(200行代码的日志组件): 一:不依赖于第三方插件和支持.net2.0 二:支持多线程高并发 三:支持读写双缓冲对列 四:自定义日志缓冲区大小 五:支持即时触发刷盘机制 六:先按日期再按文件大小RollingFile日志 七:支持日志存储位置,日志文件前缀

NLogger特点(200行代码的日志组件):

一:不依赖于第三方插件和支持.net2.0

二:支持多线程高并发

三:支持读写双缓冲对列

四:自定义日志缓冲区大小

五:支持即时触发刷盘机制

六:先按日期再按文件大小RollingFile日志

七:支持日志存储位置,日志文件前缀的个性化定义

一:为什么要特别强调不依赖于第三方插件和支持.net2.0

NLogger包括名称空间也未超过200行代码,可见日志是相当轻量级的,如果是依赖于第三方软件的支持,有失轻量级的定义。

NLogger的第一个版本是基本于.net4.0开发,但是发现在实际应用的时候很难降级到.net2.0的项目,因为第一个版本用到了很多.net4.0的特性,主要表现在:

1,多线程处理是用的Task

2,内存数据存储是用的Tuple<>

3,集合并发处理是用的 ConcurrentQueue

4,用了Linq语法

如此多的.net4特性降级到.net2.0,确实花费了很多时间来重构这个代码,举个例子:

.net2.0与.net4.0在数据集合上的运用,表现的最为不同的就是:

.net2.0 不支持集合的并发处理,如果是多线程操纵集合,必须要借助于lock来锁定对象,然而lock后的集合就从多线程变为单线程的处理了,如此的性能很让人沮丧。

.net4.0引入的Concurrent系列的并发集合,让很多不会多线程编程的伙伴都把多线程玩的溜溜转,性能还如此的高。

二:支持多线程高并发

良好的日志应用组件,支持多线程高并发是必不可少的特性。先标记一下测试机的硬件环境

,不同的硬件环境对测试结果是有较大影响的。

测试代码:

开启10个线程,每个线程写入10W数据,确认一下代码中数值0的个数是否正确:

for (int count = 0; count < 10; count++) { Thread writeThread = new Thread(new ParameterizedThreadStart((para) => { Console.WriteLine(, para)); Stopwatch sw = new Stopwatch(); sw.Start(); for (int i = 0; i < 100000; i++) { NLogger.WriteLog(, , i.ToString())); } sw.Stop(); Console.WriteLine(, para, sw.ElapsedMilliseconds)); })); writeThread.IsBackground = true; writeThread.Start(count); }

测试结果:

11秒的时间就把100W条数据刷到了缓存里。在4G内存的笔记本里,处理速度能达到10W条/秒。

三:为什么要用读写双缓冲队列

在操作第二步的时候,业务程序写入的100W条数据,绝大多数还在缓存对列里,还没有持久化到硬盘上,可以通过如下代码监视读写缓存和已持久化到硬盘上的数据。  

Thread watchThread = new Thread(new ParameterizedThreadStart((para) => { DateTime startDT = DateTime.Now; while (NLogger.totalCount < 1000000) { DateTime sectionDt = DateTime.Now; TimeSpan ts = sectionDt - startDT; Console.WriteLine(, (int)ts.TotalSeconds, NLogger.totalCount, NLogger.writeQueue.Count, NLogger.readQueue.Count)); Thread.Sleep(1000); } })); watchThread.IsBackground = true; watchThread.Start("");

可以看到在第10秒的时候,100W条数据已经被业务程序全部处理完成。其中有近83W条数据在缓存里,有13W条数据已经刷到了硬盘里,因是为按秒监控,有4W条数据的误差。持续了50秒,才把100W条数据全部刷到硬盘里。

四:自定义日志缓冲区大小

大量的日志存储在缓冲队列里,在刷新硬盘的时候,不可能一条一条的刷新数据,虽然现在的固态硬盘已经在市场上流行了很多年,还是没有完全普及,在很多计算机上IO还是瓶颈。如果能做到一次能刷新多条数据,就会提高刷盘的速度。每次刷多少数据到硬盘才能达到最优值?本机是设置的64KB,不同的计算机可能这个值有所不同。

具体的实现代码如下:

while (true) { if (readQueue.Count > 0) { string[] qItem = readQueue.Dequeue() as string[]; totalCount = totalCount + 1; string[] tempItem = tempQueue.Find(d => d[0] == qItem[0] && d[1] == qItem[1]); if (tempItem == null) { tempQueue.Add(qItem); } else { tempItem[2] = string.Concat(tempItem[2], Environment.NewLine, qItem[2]); if (tempItem[2].Length > 64 * 1024) //(1 * 1024 * 1024 = 1M); { break; } } } else { break; } }

五:支持即时触发刷盘机制

在多线程的世界里, AutoResetEvent, ManualResetEvent这两个类是十分重要的。它们的区别,网上是到处都有介绍的,本篇博客就只做一个入门级的介绍。

这两个类称为信号量类,主要包括如下三个方法:

WaitOne()

Set()

Reset()

如果把线程比作水管,WaitOne() 就是水阀,Set()就是通知打开水阀,Reset()就是通知关闭水阀。介绍信号量的博客都喜欢举这个例子,照葫芦画瓢引用了这个例子。

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • 高性能移动端开发 - beidan

    高性能移动端开发 - beidan

    2017-02-09 12:00

  • 性能优化实战案例——助力某移动OA系统 - Double_K

    性能优化实战案例——助力某移动OA系统 - Double_K

    2017-01-19 15:00

  • 使用Html5+C#+微信 开发移动端游戏详细教程:(六)游戏界面布局与性能优化 - 乔克灬叔叔

    使用Html5+C#+微信 开发移动端游戏详细教程:(六)游戏界面布局与性

    2017-01-08 09:00

  • 30分钟带你熟练性能优化的那点儿事儿(案例说明) - Double_K

    30分钟带你熟练性能优化的那点儿事儿(案例说明) - Double_K

    2016-12-13 11:00

网友点评
p