后台工作人员行为怪异?
Posted
技术标签:
【中文标题】后台工作人员行为怪异?【英文标题】:Backgroundworker acting weird? 【发布时间】:2021-03-04 03:44:20 【问题描述】:我目前正在处理一个多线程项目,该项目涉及多个并行运行的耗时任务。
每个任务都记录在同一个文件中,我需要保持整洁(以正确的顺序),所以我找到了一种“逐个任务”记录的方法:
当任务必须写入日志文件时,我将日志写入字典:_logList[id].Add(message)
此字典的 Key = ThreadID,Value = 具有此 ID 的工作人员的日志(字符串列表)
ThreadID 来自Thread.CurrentThread.ManagedThreadId
这是我启动 BackgroundWorkers 的方式:
foreach (MyTask task in List<MyTask> tasks)
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += bgworker_DoWork;
bg.RunWorkerCompleted += bgworker_RunWorkerCompleted;
List<object> arguments = new List<object>() task, args1 ;
bg.RunWorkerAsync(arguments);
bgworker_DoWork 委托是耗时的任务,写入日志。
然后,当一个任务结束时,BackgroundWorker 运行委托 bgworker_RunWorkerCompleted,这基本上结束了任务并写入了相应的日志,顺序正确:
Log.FlushWrite((int)result[2]); -- result[2] contains the threadId to flush
而FlushWrite只将threadId的日志列表写入日志文件:
WriteMessageToFile(_logList[id]);
大多数时候,这是可行的。但有时,我会看到一种奇怪的行为:
多个任务使用相同的 ThreadID 当 ThreadID X 的第一个任务 N 结束时,它调用 RunWorkerCompleted 委托,并刷新其日志 + 仅 ThreadID X 的下一个任务 N+1 的一部分(因为任务尚未结束) 当任务N+1真正结束时,它会刷新剩余的日志写入,但是日志文件因为不整洁而一团糟!我知道托管线程 id 可能会被回收和重用,但 imo 发生这种情况的唯一方法是线程已经被重用(对 DoWork
的新调用),而正在运行的 BackgroundWorker 尚未调用 @ 987654328@
我说的对吗?这种情况有什么我不明白的地方吗?
在这种情况下,也许使用 ManagedThreadId 作为字典的键是一种不好的做法?
感谢您的帮助:)
【问题讨论】:
确实,当您 [可能] 有独特的任务时,为什么要使用 ManagedThreadId 作为键(仅对其唯一性的弱假设)?为什么不使用 MyTask 作为字典键?但是您仍然可以做得更好并将记录器传递给 gbWorker_doWork。最后,为什么要使用 BackgroundWorker?您正在开发一个 winforms 应用程序吗? 我认为使用 ManagedThreadId 是最简单的键。确实我的任务是独一无二的,所以我可以把它当作关键!传递记录器是什么意思,这怎么行?最后我只知道BackgroundWorker的多线程:我不是在开发一个winform应用程序,你认为我不应该使用这个类来完成我的任务吗?你有什么建议? :) 谢谢 如果您需要报告进度,我建议使用Task.Run
和async/await,而不是BackgroundWorker
,并结合Progress<T>
。您可以看到here 两个选项之间的实际比较。今天使用BackgroundWorker
s 进行新开发的唯一理由是在维护旧版应用程序时,这些应用程序在过期版本的 .NET Framework 上运行。
@TheodorZoulias 感谢您的回答。我无法更改为 Task.Run 但如果我仍然使用 ManagedThreadId 作为密钥,您认为它会解决我的日志记录问题吗?或者你的意思是我应该使用 ProgressTask.Run
和 async/await 作为过时 BackgroundWorker
的现代替代品。如果您不能使用Task.Run
,那么使用Progress<T>
的价值就会相应减少。 BackgroundWorker
配备了自己的进度报告机制,为什么要混用呢?
【参考方案1】:
我发现了我的问题:在FlushWrite
操作期间,执行了锁定。如果worker等待的时间过长,另一个worker可能会写入相同的ThreadID,因此在这种情况下操作的flush是不一致的。
通过使用另一个字典解决,仅用于刷新“完整工人”。
代码也被重写以将BackGroundWorker
更改为Task.Run
。谢谢:)
【讨论】:
以上是关于后台工作人员行为怪异?的主要内容,如果未能解决你的问题,请参考以下文章