后台工作人员行为怪异?

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&lt;T&gt;。您可以看到here 两个选项之间的实际比较。今天使用BackgroundWorkers 进行新开发的唯一理由是在维护旧版应用程序时,这些应用程序在过期版本的 .NET Framework 上运行。 @TheodorZoulias 感谢您的回答。我无法更改为 Task.Run 但如果我仍然使用 ManagedThreadId 作为密钥,您认为它会解决我的日志记录问题吗?或者你的意思是我应该使用 Progress 来写日志? 对不起,你的问题太复杂了,我无法理解,所以我真的无法提供任何关于如何解决它的建议。我刚刚提到了 Task.Run 和 async/await 作为过时 BackgroundWorker 的现代替代品。如果您不能使用Task.Run,那么使用Progress&lt;T&gt; 的价值就会相应减少。 BackgroundWorker 配备了自己的进度报告机制,为什么要混用呢? 【参考方案1】:

我发现了我的问题:在FlushWrite 操作期间,执行了锁定。如果worker等待的时间过长,另一个worker可能会写入相同的ThreadID,因此在这种情况下操作的flush是不一致的。

通过使用另一个字典解决,仅用于刷新“完整工人”。

代码也被重写以将BackGroundWorker 更改为Task.Run。谢谢:)

【讨论】:

以上是关于后台工作人员行为怪异?的主要内容,如果未能解决你的问题,请参考以下文章

fstream 行为怪异

JFrame 行为怪异

位置服务行为怪异

估计HeightForHeaderInSection 行为怪异

访问:DSUM 行为怪异

ScrollPanel ( height ) 怪异行为 GWT,