cpu:i5-8265U 硬盘:固态硬盘 测试结果:每秒写入文件大约1万到3万条日志,每条日志的字符串长度是140多个字符@H_502_2@
支持多线程并发,支持多进程并发,支持按文件大小分隔日志文件@H_502_2@
LogUtil.cs代码:
using@H_502_2@ System;
@H_502_2@ System.Collections.Concurrent;
@H_502_2@ System.Collections.Generic;
@H_502_2@ System.IO;
@H_502_2@ System.Linq;
@H_502_2@ System.Reflection;
@H_502_2@ System.Text;
@H_502_2@ System.Text.RegularExpressions;
@H_502_2@ System.Threading;
@H_502_2@ System.Threading.Tasks;
@H_502_2@namespace@H_502_2@ Utils
{
@H_502_2@///@H_502_2@ <summary>@H_502_2@
///@H_502_2@ 写日志类
@H_502_2@</summary>@H_502_2@
public@H_502_2@ class@H_502_2@ LogUtil
{
@H_502_2@#region@H_502_2@ 字段
private@H_502_2@ static@H_502_2@ string@H_502_2@ _path = null@H_502_2@;
@H_502_2@static@H_502_2@ Mutex _mutex = new@H_502_2@ Mutex(false@H_502_2@,"@H_502_2@LogUtil.Mutex.180740C3B1C44D428683D35F84F97E22@H_502_2@"@H_502_2@);
@H_502_2@static@H_502_2@ ConcurrentDictionary<string@H_502_2@,int@H_502_2@> _dictIndex = new@H_502_2@ ConcurrentDictionary<int@H_502_2@>();
@H_502_2@long@H_502_2@> _dictSize = long@H_502_2@>();
@H_502_2@string@H_502_2@> _dictPathFolders = string@H_502_2@>static@H_502_2@ TaskSchedulerEx _scheduler = new@H_502_2@ TaskSchedulerEx(2@H_502_2@,1)">2@H_502_2@int@H_502_2@ _fileSize = 10@H_502_2@ * 1024@H_502_2@ * 1024@H_502_2@; //@H_502_2@日志分隔文件大小@H_502_2@
#endregion@H_502_2@
#region@H_502_2@ 写文件
<summary>@H_502_2@
写文件
@H_502_2@</summary>@H_502_2@
void@H_502_2@ WriteFile(LogType logType,1)">string@H_502_2@ log,1)">string@H_502_2@ path)
{
@H_502_2@try@H_502_2@
{
FileStream fs @H_502_2@= ;
StreamWriter sw @H_502_2@= ;
@H_502_2@if@H_502_2@ (!(_dictStream.TryGetValue(logType.ToString() + path,1)">out@H_502_2@ fs) && _dictWriter.TryGetValue(logType.ToString() + path,1)">out@H_502_2@ sw)))
{
@H_502_2@foreach@H_502_2@ (string@H_502_2@ key in@H_502_2@ _dictWriter.Keys)
{
@H_502_2@if@H_502_2@ (key.StartsWith(logType.ToString()))
{
StreamWriter item;
_dictWriter.TryRemove(key,@H_502_2@ item);
item.Close();
}
}
@H_502_2@ _dictStream.Keys)
{
@H_502_2@ (key.StartsWith(logType.ToString()))
{
FileStream item;
_dictStream.TryRemove(key,1)">if@H_502_2@ (!Directory.Exists(Path.GetDirectoryName(path)))
{
Directory.CreateDirectory(Path.GetDirectoryName(path));
}
fs @H_502_2@= new@H_502_2@ FileStream(path,FileMode.Append,FileAccess.Write,FileShare.ReadWrite);
sw @H_502_2@= StreamWriter(fs);
_dictWriter.TryAdd(logType.ToString() @H_502_2@+ path,sw);
_dictStream.TryAdd(logType.ToString() @H_502_2@+502_2@0@H_502_2@,SeekOrigin.End);
sw.WriteLine(log);
sw.Flush();
fs.Flush();
}
@H_502_2@catch@H_502_2@ (Exception ex)
{
@H_502_2@string@H_502_2@ str = ex.Message;
}
}
@H_502_2@#region@H_502_2@ 生成日志文件路径
生成日志文件路径
@H_502_2@string@H_502_2@ CreateLogPath(LogType logType,1)"> log)
{
@H_502_2@
{
@H_502_2@if@H_502_2@ (_path == )
{
UriBuilder uri @H_502_2@= UriBuilder(Assembly.GetExecutingAssembly().CodeBase);
_path @H_502_2@= Path.GetDirectoryName(Uri.UnescapeDataString(uri.Path));
}
@H_502_2@string@H_502_2@ pathFolder = Path.Combine(_path,1)">Log\\@H_502_2@"@H_502_2@ + logType.ToString() + \\@H_502_2@);
@H_502_2@_dictPathFolders.ContainsKey(pathFolder))
{
@H_502_2@Directory.Exists(Path.GetDirectoryName(pathFolder)))
{
Directory.CreateDirectory(Path.GetDirectoryName(pathFolder));
}
_dictPathFolders.TryAdd(pathFolder,pathFolder);
}
@H_502_2@int@H_502_2@ currentIndex;
@H_502_2@long@H_502_2@ size;
@H_502_2@string@H_502_2@ strNow = DateTime.Now.ToString(yyyyMMdd@H_502_2@string@H_502_2@ strKey = pathFolder + strNow;
@H_502_2@if@H_502_2@ (!(_dictIndex.TryGetValue(strKey,1)">out@H_502_2@ currentIndex) && _dictSize.TryGetValue(strKey,1)"> size)))
{
_dictIndex.Clear();
_dictSize.Clear();
GetIndexAndSize(pathFolder,strNow,1)">out@H_502_2@ currentIndex,1)"> size);
@H_502_2@if@H_502_2@ (size >= _fileSize) currentIndex++;
_dictIndex.TryAdd(strKey,currentIndex);
_dictSize.TryAdd(strKey,size);
}
@H_502_2@int@H_502_2@ index = _dictIndex[strKey];
@H_502_2@string@H_502_2@ logPath = Path.Combine(pathFolder,strNow + (index == 1@H_502_2@ ? ""@H_502_2@ : _@H_502_2@"@H_502_2@ + index.ToString()) + .txt@H_502_2@);
_dictSize[strKey] @H_502_2@+= Encoding.UTF8.GetByteCount(log);
@H_502_2@if@H_502_2@ (_dictSize[strKey] > _fileSize)
{
_dictIndex[strKey]@H_502_2@++;
_dictSize[strKey] @H_502_2@= ;
}
@H_502_2@return@H_502_2@ logPath;
}
@H_502_2@ ex.Message;
@H_502_2@return@H_502_2@ ;
}
}
@H_502_2@#region@H_502_2@ 拼接日志内容
拼接日志内容
@H_502_2@string@H_502_2@ CreateLogString(LogType logType,1)">string@H_502[email protected](@"@H_502_2@{0} {1} {2}@H_502_2@"@H_502_2@,DateTime.Now.ToString(yyyy-MM-dd HH:mm:ss.fff@H_502_2@"@H_502_2@),([@H_502_2@]@H_502_2@"@H_502_2@).padright(7@H_502_2@,1)">'@H_502_2@ '@H_502_2@),log);
}
@H_502_2@#region@H_502_2@ 获取初始Index和Size
获取初始Index和Size
@H_502_2@void@H_502_2@ GetIndexAndSize(string@H_502_2@ pathFolder,1)">string@H_502_2@ strNow,1)">out@H_502_2@ int@H_502_2@ index,1)"> size)
{
index @H_502_2@= 1@H_502_2@;
size @H_502_2@= ;
Regex regex @H_502_2@= new@H_502_2@ Regex(strNow + _*(\\d*).txt@H_502_2@);
@H_502_2@string@H_502_2@[] fileArr = Directory.GetFiles(pathFolder);
@H_502_2@string@H_502_2@ currentFile = ;
@H_502_2@string@H_502_2@ file fileArr)
{
Match match @H_502_2@= regex.Match(file);
@H_502_2@ (match.Success)
{
@H_502_2@string@H_502_2@ str = match.Groups[].Value;
@H_502_2@.IsNullOrWhiteSpace(str))
{
@H_502_2@int@H_502_2@ temp = Convert.ToInt32(str);
@H_502_2@if@H_502_2@ (temp > index)
{
index @H_502_2@= temp;
currentFile @H_502_2@= file;
}
}
@H_502_2@else@H_502_2@
{
index @H_502_2@= ;
currentFile @H_502_2@= file;
}
}
}
@H_502_2@if@H_502_2@ (currentFile != )
{
FileInfo fileInfo @H_502_2@= FileInfo(currentFile);
size @H_502_2@= fileInfo.Length;
}
}
@H_502_2@#region@H_502_2@ 写调试日志
写调试日志
@H_502_2@static@H_502_2@ Task Debug(return@H_502_2@ Task.Factory.StartNew(() =>
{
_mutex.WaitOne();
log @H_502_2@= CreateLogString(LogType.Debug,log);
@H_502_2@string@H_502_2@ path = CreateLogPath(LogType.Debug,log);
WriteFile(LogType.Debug,log,path);
}
@H_502_2@ (Exception ex)
{
@H_502_2@ ex.Message;
}
@H_502_2@finally@H_502_2@
{
_mutex.ReleaseMutex();
}
},CancellationToken.None,TaskCreationoptions.None,_scheduler);
}
@H_502_2@#region@H_502_2@ 写错误日志
static@H_502_2@ Task Error(Exception ex,1)">string@H_502_2@ log = )
{
@H_502_2@return@H_502_2@ Error(string@H_502[email protected](log) ? ex.Message + \r\n@H_502_2@"@H_502_2@ + ex.StackTrace : (log + :@H_502_2@"@H_502_2@) + ex.Message + "@H_502_2@ + ex.StackTrace);
}
@H_502_2@ 写错误日志
@H_502_2@static@H_502_2@ Task Error( CreateLogString(LogType.Error,1)"> CreateLogPath(LogType.Error,log);
WriteFile(LogType.Error,1)">#region@H_502_2@ 写操作日志
写操作日志
@H_502_2@static@H_502_2@ Task Log( CreateLogString(LogType.Info,1)"> CreateLogPath(LogType.Info,log);
WriteFile(LogType.Info,1)">#endregion@H_502_2@
}
@H_502_2@#region@H_502_2@ 日志类型
日志类型
@H_502_2@enum@H_502_2@ LogType
{
Debug,Info,Error
}
@H_502_2@
}@H_502_2@
依赖的TaskSchedulerEx.cs代码:
System.Runtime.InteropServices;
@H_502_2@ TaskScheduler扩展
@H_502_2@ 每个实例都是独立线程池
@H_502_2@ TaskSchedulerEx : TaskScheduler,Idisposable
{
@H_502_2@#region@H_502_2@ 外部方法
[DllImport(@H_502_2@kernel32.dll@H_502_2@SetProcessWorkingSetSize@H_502_2@)]
@H_502_2@extern@H_502_2@ int@H_502_2@ SetProcessWorkingSetSize(IntPtr process,1)">int@H_502_2@ minSize,1)"> maxSize);
@H_502_2@#region@H_502_2@ 变量属性事件
private@H_502_2@ ConcurrentQueue<Task> _tasks = new@H_502_2@ ConcurrentQueue<Task>int@H_502_2@ _coreThreadCount = ;
@H_502_2@int@H_502_2@ _maxThreadCount = int@H_502_2@ _auxiliaryThreadTimeOut = 20000@H_502_2@; 辅助线程释放时间@H_502_2@
int@H_502_2@ _activeThreadCount = private@H_502_2@ System.Timers.Timer _timer;
@H_502_2@object@H_502_2@ _lockCreateTimer = new@H_502_2@ object@H_502_2@bool@H_502_2@ _run = true@H_502_2@private@H_502_2@ AutoResetEvent _evt = new@H_502_2@ AutoResetEvent(false@H_502_2@);
@H_502_2@ 活跃线程数
@H_502_2@ ActiveThreadCount
{
@H_502_2@get@H_502_2@ { _activeThreadCount; }
}
@H_502_2@ 核心线程数
@H_502_2@ CoreThreadCount
{
@H_502_2@ _coreThreadCount; }
}
@H_502_2@ 最大线程数
@H_502_2@ MaxThreadCount
{
@H_502_2@ _maxThreadCount; }
}
@H_502_2@#region@H_502_2@ 构造函数
TaskScheduler扩展
@H_502_2@ 每个实例都是独立线程池
@H_502_2@</summary>@H_502_2@
<param name="coreThreadCount">@H_502_2@核心线程数(大于或等于0,不宜过大)(如果是一次性使用,则设置为0比较合适)@H_502_2@</param>@H_502_2@
<param name="maxThreadCount">@H_502_2@最大线程数@H_502_2@</param>@H_502_2@
public@H_502_2@ TaskSchedulerEx(int@H_502_2@ coreThreadCount = 10@H_502_2@,1)">int@H_502_2@ maxThreadCount = 20@H_502_2@)
{
_maxThreadCount @H_502_2@= maxThreadCount;
CreateCoreThreads(coreThreadCount);
}
@H_502_2@#region@H_502_2@ override GetScheduledTasks
protected@H_502_2@ override@H_502_2@ IEnumerable<Task> GetScheduledTasks()
{
@H_502_2@ _tasks;
}
@H_502_2@#region@H_502_2@ override TryExecuteTaskInline
override@H_502_2@ bool@H_502_2@ TryExecuteTaskInline(Task task,1)">bool@H_502_2@ taskwasprevIoUslyQueued)
{
@H_502_2@;
}
@H_502_2@#region@H_502_2@ override QueueTask
void@H_502_2@ QueueTask(Task task)
{
CreateTimer();
_tasks.Enqueue(task);
_evt.Set();
}
@H_502_2@#region@H_502_2@ 资源释放
资源释放
@H_502_2@ 队列中尚未执行的任务不再执行
@H_502_2@ dispose()
{
_run @H_502_2@= ;
@H_502_2@if@H_502_2@ (_timer != )
{
_timer.Stop();
_timer.dispose();
_timer @H_502_2@= ;
}
@H_502_2@while@H_502_2@ (_activeThreadCount > )
{
_evt.Set();
}
}
@H_502_2@#region@H_502_2@ 创建核心线程池
创建核心线程池
@H_502_2@void@H_502_2@ CreateCoreThreads(int@H_502_2@? coreThreadCount = if@H_502_2@ (coreThreadCount != null@H_502_2@) _coreThreadCount = coreThreadCount.Value;
@H_502_2@for@H_502_2@ (int@H_502_2@ i = 0@H_502_2@; i < _coreThreadCount; i++)
{
Interlocked.Increment(@H_502_2@ref@H_502_2@ _activeThreadCount);
Thread thread @H_502_2@= ;
thread @H_502_2@= new@H_502_2@ Thread(new@H_502_2@ ThreadStart(() =>
{
Task task;
@H_502_2@while@H_502_2@ (_run)
{
@H_502_2@if@H_502_2@ (_tasks.TryDequeue( task))
{
TryExecuteTask(task);
}
@H_502_2@
{
_evt.WaitOne();
}
}
Interlocked.Decrement(@H_502_2@ _activeThreadCount);
@H_502_2@if@H_502_2@ (_activeThreadCount == )
{
GC.Collect();
GC.WaitForPendingFinalizers();
@H_502_2@if@H_502_2@ (Environment.Osversion.Platform == PlatformID.Win32NT)
{
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle,@H_502_2@-1@H_502_2@,-);
}
}
}));
thread.IsBackground @H_502_2@= ;
thread.Start();
}
}
@H_502_2@#region@H_502_2@ 创建辅助线程
创建辅助线程
@H_502_2@ CreateThread()
{
Interlocked.Increment(@H_502_2@ _activeThreadCount);
Thread thread @H_502_2@= ;
thread @H_502_2@=
{
Task task;
DateTime dt @H_502_2@= DateTime.Now;
@H_502_2@while@H_502_2@ (_run && DateTime.Now.Subtract(dt).TotalMilliseconds < _auxiliaryThreadTimeOut)
{
@H_502_2@ task))
{
TryExecuteTask(task);
dt @H_502_2@= DateTime.Now;
}
@H_502_2@
{
_evt.WaitOne(_auxiliaryThreadTimeOut);
}
}
Interlocked.Decrement(@H_502_2@ _activeThreadCount);
@H_502_2@if@H_502_2@ (_activeThreadCount == _coreThreadCount)
{
GC.Collect();
GC.WaitForPendingFinalizers();
@H_502_2@ PlatformID.Win32NT)
{
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle,1)">);
}
}
}));
thread.IsBackground @H_502_2@= ;
thread.Start();
}
@H_502_2@#region@H_502_2@ 创建定时器
CreateTimer()
{
@H_502_2@if@H_502_2@ (_timer == null@H_502_2@) _timer不为空时,跳过,不走lock,提升性能@H_502_2@
{
@H_502_2@if@H_502_2@ (_activeThreadCount >= _coreThreadCount && _activeThreadCount < _maxThreadCount) 活跃线程数达到最大线程数时,跳过,不走lock,提升性能@H_502_2@
{
@H_502_2@lock@H_502_2@ (_lockCreateTimer)
{
@H_502_2@)
{
_timer @H_502_2@= System.Timers.Timer();
_timer.Interval @H_502_2@= _coreThreadCount == 0@H_502_2@ ? 1@H_502_2@ : 500@H_502_2@;
_timer.Elapsed @H_502_2@+= (s,e) =>
{
@H_502_2@if@H_502_2@ (_activeThreadCount >= _coreThreadCount && _activeThreadCount < _maxThreadCount)
{
@H_502_2@if@H_502_2@ (_tasks.Count > )
{
@H_502_2@if@H_502_2@ (_timer.Interval != 20@H_502_2@) _timer.Interval = ;
CreateThread();
}
@H_502_2@
{
@H_502_2@500@H_502_2@) _timer.Interval = ;
}
}
@H_502_2@
{
@H_502_2@)
{
_timer.Stop();
_timer.dispose();
_timer @H_502_2@= ;
}
}
};
_timer.Start();
}
}
}
}
}
@H_502_2@#region@H_502_2@ 全部取消
全部取消
@H_502_2@ 取消队列中尚未执行的任务
@H_502_2@ CancelAll()
{
Task tempTask;
@H_502_2@while@H_502_2@ (_tasks.TryDequeue( tempTask)) { }
}
@H_502_2@
}
}@H_502_2@
依赖的RunHelper.cs代码:
线程工具类
@H_502_2@ RunHelper
{
@H_502_2@#region@H_502_2@ 变量属性事件
#region@H_502_2@ 线程中执行
线程中执行
@H_502_2@static@H_502_2@ Task Run(this@H_502_2@ TaskScheduler scheduler,Action<object@H_502_2@> doWork,1)">object@H_502_2@ arg = null@H_502_2@,Action<Exception> errorAction = return@H_502_2@ Task.Factory.StartNew((obj) =>
{
doWork(obj);
}
@H_502_2@if@H_502_2@ (errorAction != ) errorAction(ex);
LogUtil.Error(ex,@H_502_2@ThreadUtil.Run错误@H_502_2@);
}
},arg,scheduler);
}
@H_502_2@
{
doWork();
}
@H_502_2@static@H_502_2@ Task<T> Run<T>(object@H_502_2@,T> doWork,1)">return@H_502_2@ Task.Factory.StartNew<T>((obj) =>
{
@H_502_2@ doWork(obj);
}
@H_502_2@);
@H_502_2@default@H_502_2@(T);
}
},Func<T> doWork,1)">return@H_502_2@ Task.Factory.StartNew<T>(() => doWork();
}
@H_502_2@async@H_502_2@ Task<T> RunAsync<T>(await@H_502_2@ Task.Factory.StartNew<T>((obj) =>await@H_502_2@ Task.Factory.StartNew<T>(() =>
}
}@H_502_2@
测试代码:
System.ComponentModel;
@H_502_2@ System.Data;
@H_502_2@ System.Diagnostics;
@H_502_2@ System.Drawing;
@H_502_2@ System.Threading.Tasks;
@H_502_2@ System.Windows.Forms;
@H_502_2@ Utils;
@H_502_2@ LogUtilTest
{
@H_502_2@partial@H_502_2@ Form1 : Form
{
@H_502_2@public@H_502_2@ Form1()
{
InitializeComponent();
}
@H_502_2@void@H_502_2@ button1_Click( sender,EventArgs e)
{
Task.Factory.StartNew(() @H_502_2@=>int@H_502_2@ n = 100000@H_502_2@;
@H_502_2@string@H_502_2@ processId = Process.GetCurrentProcess().Id.ToString().PadLeft(8@H_502_2@,1)">);
List@H_502_2@<Task> taskList = new@H_502_2@ List<Task>();
@H_502_2@string@H_502_2@ str = abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcda3.1415bcdabcdabcdabcdabc@#$%^&dabcdabcdabcdabcdabcdabcdabcdabcd@H_502_2@;
DateTime dtStart @H_502_2@=1@H_502_2@; i <= n; i++)
{
Task task @H_502_2@= LogUtil.Log(ProcessId:【@H_502_2@"@H_502_2@ + processId + 】 测试@H_502_2@"@H_502_2@ + i.ToString().PadLeft('@H_502_2@0@H_502_2@'@H_502_2@) + str);
taskList.Add(task);
task @H_502_2@= LogUtil.Debug( str);
taskList.Add(task);
}
Task.WaitAll(taskList.ToArray());
@H_502_2@double@H_502_2@ sec = DateTime.Now.Subtract(dtStart).TotalSeconds;
MessageBox.Show(n @H_502_2@+ 条日志完成,耗时@H_502_2@"@H_502_2@ + sec.ToString(0.000@H_502_2@"@H_502_2@) + 秒@H_502_2@);
});
}
}
}@H_502_2@
测试结果截图:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。