关于WPF MaterialDesign 示例的开源项目
本文讲解"关于WPF MaterialDesign 示例的开源项目",用于解决相关问题。
【WPF MaterialDesign 示例开源项目】 Work Time Manager
今天,我们聊聊客户端的日志组件。
我也不知道说组件合不合适,反正就是属于软件一部分并且可以被重复利用的小模块我称之为组件。
这次的日志类就是很典型的一个组件,日志有很多特点;
1、会被使用在软件的任意一个地方
2、随时都会被调用
3、使用率极高
4、频繁的io操作
在我刚刚接触c#的时候,就使用过了Log4net,但是,那时候就萌生的想法是,我一个程序可能也才几m大小,一个日志组件就比上我一个主程序了,这明显是不合适的。
于是两年前还没有毕业的我着手做了自己的第一个日志组件。
【.net】创建属于自己的log组件——改进版
基础的思想还是好的,包括:线程,阻塞,资源竞争等都做了一定的考虑。
俗话说初生牛犊不怕虎,啥也不太知道的自己就这么开干了。
写了第一版通过开线程来做的日志组件。
可是,毕竟年轻,问题还是显而易见的。一秒打100条就不行了。
于是在我重新着手c#开发的时候,抽了点时间,来了一次重构。
首先,从整体架构下手:- 旧组件特点:* 使用多线程队列,用互斥变量控制线程对文本的写入。* 通过单例加锁的方式,控制资源的争夺* 线程是随机被选中入锁的,写入的日志时间顺序可能不对* 一个线程一次文本操作,开关都在一个线程操作,一次只写入一条变量- 优点:* 多线程操作,表面提高操作效率 * 单例加锁,确保唯一- 缺点:* 性能底下,过度操作io导致性能严重冗余* 一次只写一条- 改进* 使用生产者消费者模式,分开操作,限制线程数量* 使用栈队列,先进先出,保证日志顺序* 单例IO变量,批量进行写入操作改造成果:
using System;using System.Collections;using System.IO;using System.Text;using System.Threading;using System.Windows.Threading;namespace Helper {public static class LogHelper {private static readonly Queue LogQueue = new Queue();private static bool _isStreamClose = true;private static bool _isThreadBegin = false;private static StreamWriter _fileStreamWriter;private static readonly string fileName =@"BugLog.txt";static int _intervalTime = 10000;// 10sstatic System.Timers.Timer _timer = new System.Timers.Timer(_intervalTime);/// <summary>/// 添加日志队列/// </summary>/// <param name="message"></param>public static void AddLog(string message) {string logContent = $"[{DateTime.Now:yyyy-MM-dd hh:mm:ss}] =>{message}"; LogQueue.Enqueue(logContent);if (!_isThreadBegin) { BeginThread(); } }public static void AddLog(Exception ex) {var logContent = $"[{DateTime.Now:yyyy-MM-dd hh:mm:ss}]错误发生在:{ex.Source},\r\n 内容:{ex.Message}"; logContent += $"\r\n 跟踪:{ex.StackTrace}"; LogQueue.Enqueue(logContent);if (!_isThreadBegin) { BeginThread(); } }/// <summary>/// 读取日志队列的一条数据/// </summary>/// <returns></returns>private static object GetLog() {return LogQueue.Dequeue(); }/// <summary>/// 开启定时查询线程/// </summary>public static void BeginThread() { _isThreadBegin = true;//实例化Timer类,设置间隔时间为10000毫秒; _timer.Interval = _intervalTime; _timer.Elapsed += SetLog;//到达时间的时候执行事件; _timer.AutoReset = true;//设置是执行一次(false)还是一直执行(true); _timer.Enabled = true; }/// <summary>/// 写入日志/// </summary>private static void SetLog(object source, System.Timers.ElapsedEventArgs e) {if (LogQueue.Count == 0) {if (_isStreamClose) return; _fileStreamWriter.Flush(); _fileStreamWriter.Close(); _isStreamClose = true;return; }if (_isStreamClose) { Isexist();string errLogFilePath = Environment.CurrentDirectory + @"\Log\" + fileName.Trim();if (!File.Exists(errLogFilePath)) { FileStream fs1 = new FileStream(errLogFilePath, FileMode.Create, FileAccess.Write); _fileStreamWriter = new StreamWriter(fs1); }else{ _fileStreamWriter = new StreamWriter(errLogFilePath, true); } _isStreamClose = false; }var strLog = new StringBuilder();var onceTime = 50;var lineNum = LogQueue.Count > onceTime ? onceTime : LogQueue.Count;for (var i = 0; i < lineNum; i++) { strLog.AppendLine(GetLog().ToString()); } _fileStreamWriter.WriteLine(strLog.ToString()); }/// <summary>/// 判断是否存在日志文件/// </summary>private static void Isexist() {string path = Environment.CurrentDirectory + @"\Log\";if (!File.Exists(path)) { Directory.CreateDirectory(path); } } } }
代码没有第三方组件的应用,直接把这个文件复制即可使用。
现在暂时没有对一些特殊情况做处理,例如日志文件被占用、软件临时关闭,以及队列触发时间和批量写入个数等考虑,这只是一个最基础的demo
关于 "关于WPF MaterialDesign 示例的开源项目" 就介绍到此。希望多多支持编程宝库。
如何实现直接调用vs反射调用的实例教程:本文讲解"怎么实现直接调用vs反射调用的实例教程",用于解决相关问题。直接调用vs反射调用下面就来写个demo来验证下直接调用和反射调用的性能差异,代码如下: 1 namespace ConsoleA ...