c# – 从BackgroundWorker转向TPL以获取日志记录类
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了c# – 从BackgroundWorker转向TPL以获取日志记录类,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4526字,纯文字阅读大概需要7分钟。
内容图文
![c# – 从BackgroundWorker转向TPL以获取日志记录类](/upload/InfoBanner/zyjiaocheng/795/e10b54bc9dc140149880023aa4ef9701.jpg)
我目前在旧的Backgroundworker类的视图中编写了一个简单的事件记录器.我试图将其转换为TPL实现.
我没有足够的使用C#中的线程来真正优先于另一个,但我知道TPL正变得越来越受欢迎,我想尽可能地坚持下去.另一个原因是,使用当前代码,我找不到一个简单的方法来使EventLog类线程安全.我发现自己使用BeginInvoke从非UI线程写入日志,这对我来说似乎很麻烦.
所以这是原始代码.
public class EventLog
{
public String LogPath { get; set; }
public List<LogEvent> Events { get; private set; }
public static EventLog Instance { get { return lazyInstance.Value; } }
private static readonly Lazy<EventLog> lazyInstance = new Lazy<EventLog>(() => new EventLog());
private EventLog()
{
Events = new List<LogEvent>();
LogPath = Assembly.GetExecutingAssembly().CodeBase;
LogPath = Path.GetDirectoryName(LogPath);
LogPath = LogPath.Replace("file:\\", "");
LogPath = LogPath + "\\Log.txt";
}
public override void publish(LogEvent newEvent)
{
Events.Add(newEvent);
if (!LogEventWriter.Instance.IsBusy)
LogEventWriter.Instance.RunWorkerAsync(LogPath);
LogEventWriter.Instance.LogEvents.Add(newEvent);
}
}
internal class LogEventWriter : BackgroundWorker
{
public BlockingCollection<LogEvent> LogEvents { get; set; }
public static LogEventWriter Instance { get { return lazyInstance.Value; } }
private static readonly Lazy<LogEventWriter> lazyInstance = new Lazy<LogEventWriter>(() => new LogEventWriter());
private LogEventWriter()
{
WorkerSupportsCancellation = true;
LogEvents = new BlockingCollection<LogEvent>();
}
protected override void OnDoWork(DoWorkEventArgs e)
{
if (e.Argument != null && e.Argument is String)
{
String logPath = (String)e.Argument;
using (StreamWriter logFile = new StreamWriter(logPath, true))
{
while (!CancellationPending)
{
LogEvent anEvent = LogEvents.Take();
logFile.WriteLine(anEvent.Message);
logFile.Flush();
if (anEvent.Message.Contains("Application Terminated"))
break;
}
logFile.Close();
}
}
e.Cancel = true;
}
}
我对日志的当前思路是在系统出现故障时尽快将日志写入文件,以便日志尽可能多地获取信息.这就是Backgroundworker的用途.我还保留了一个List< LogEvent>在EventLog类中,以便用户可以在当前日志中搜索特定事件(未完全实现/抛光).
这是我目前的TPL解决方案.我尽力将日志记录功能包装到Tasks中,但我仍然觉得我应该有一个类似于发布的函数,而不必直接将LogEvents放入BlockingCollection<>这样我就可以在主UI上的一个单独的线程上运行日志记录.
还有一种更简洁的方法来停止任务,而不必向他们发送“特殊”LogEvent来打破他们的循环?
public class EventLog
{
public static EventLog Instance { get { return lazyInstance.Value; } }
private static readonly Lazy<EventLog> lazyInstance = new Lazy<EventLog>(() => new EventLog());
public String LogPath { get; set; }
public ConcurrentQueue<LogEvent> Events { get; set; }
private EventLog()
{
Events = new ConcurrentQueue<LogEvent>();
WriteQueue = new BlockingCollection<LogEvent>();
LogEventQueue = new BlockingCollection<LogEvent>();
LogPath = Assembly.GetExecutingAssembly().CodeBase;
LogPath = Path.GetDirectoryName(LogPath);
LogPath = LogPath.Replace("file:\\", "");
LogPath = LogPath + "\\LogASDF.txt";
StartManager();
StartWriter();
}
public BlockingCollection<LogEvent> LogEventQueue { get; set; }
private void StartManager()
{
var writeTask = Task.Factory.StartNew(() =>
{
while (true)
{
LogEvent anEvent = LogEventQueue.Take();
Events.Enqueue(anEvent);
WriteQueue.Add(anEvent);
if (anEvent.Message.Contains("Application Terminated"))
break;
}
});
}
private BlockingCollection<LogEvent> WriteQueue { get; set; }
private void StartWriter()
{
var writeTask = Task.Factory.StartNew(() =>
{
using (StreamWriter logFile = new StreamWriter(LogPath, true))
{
while(true)
{
LogEvent anEvent = WriteQueue.Take();
logFile.WriteLine(anEvent.Message);
logFile.Flush();
if (anEvent.Message.Contains("Application Terminated"))
break;
}
logFile.Close();
}
});
}
}
>如何正确使用CancellationToken取消这两项任务?我不知道如果BlockingCollection被阻塞,我总是要“脉动”集合以使其解除阻塞.
>是否有一种“更清洁”的方式将LogEvent插入日志而无需直接将其插入LogEventQueue?
解决方法:
现在你的代码不是线程安全的,因为你有这个:
public List<LogEvent> Events { get; private set; }
列表与LT; T>不是线程安全的,可以从外部代码更改.而且我看不出它是否被使用过.
此外,您确实应该在代码中使用CancellationToken,因为在其他情况下您可能会遇到麻烦:例如,您有5条消息在队列中,并且您决定取消您的工作.在这种情况下,检查关闭日志只会在一段时间后中断循环,这会让您的班级最终用户感到困惑.
此外,BlockingCollection<T>.Take方法使用CancellationToken存在重载,但是如果取消,您将捕获OperationCanceledException:
try
{
LogEvent anEvent = WriteQueue.Take(CancellationPending);
}
catch (OperationCanceledException ex)
{
// handle stop here;
}
在多线程的非常糟糕的实践中无限循环,我建议不要使用它.
内容总结
以上是互联网集市为您收集整理的c# – 从BackgroundWorker转向TPL以获取日志记录类全部内容,希望文章能够帮你解决c# – 从BackgroundWorker转向TPL以获取日志记录类所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。