后台人员行为怪异?
Backgroundworker acting weird?
我目前正在处理一个涉及多个并行耗时任务的多线程项目 运行。
每个任务都在同一个文件中记录,我需要保持它的整洁(以正确的顺序),所以我找到了一种“逐个任务”记录的方法:
- 当任务必须写入日志文件时,我将日志写入字典:
_logList[id].Add(message)
- 此字典的键 = ThreadID,值 = 具有此 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 仅将线程 ID 的日志列表写入日志文件:
WriteMessageToFile(_logList[id]);
大多数情况下,这是可行的。但有时,我会看到一个奇怪的行为:
- 多个任务使用同一个 ThreadID
- 当ThreadID X的第一个任务N结束时,调用RunWorkerCompleted delegate,并刷新其日志+仅ThreadID X的下一个任务N+1的一部分(因为任务还没有结束) )
- 当N+1任务真正结束时,将剩余的日志刷新写入,但是日志文件因为不整齐,乱七八糟!
我知道托管线程 ID 可能会被回收和重用,但我认为发生这种情况的唯一方法是当 BackgroundWorker 运行 还没有调用 RunWorkerCompleted
我说得对吗?这种情况有什么不明白的地方吗?
也许在那种情况下使用 ManagedThreadId 作为字典的键是一种不好的做法?
感谢您的帮助:)
我发现了我的问题:在FlushWrite
操作期间,执行了一个锁。如果一个worker等待时间过长,另一个worker可以写入同一个ThreadID,导致本例flush操作不一致。
通过使用另一个字典解决,仅用于冲洗“完全工人”。
代码也已重写,将 BackGroundWorker
更改为 Task.Run
。谢谢:)
我目前正在处理一个涉及多个并行耗时任务的多线程项目 运行。
每个任务都在同一个文件中记录,我需要保持它的整洁(以正确的顺序),所以我找到了一种“逐个任务”记录的方法:
- 当任务必须写入日志文件时,我将日志写入字典:
_logList[id].Add(message)
- 此字典的键 = ThreadID,值 = 具有此 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 仅将线程 ID 的日志列表写入日志文件:
WriteMessageToFile(_logList[id]);
大多数情况下,这是可行的。但有时,我会看到一个奇怪的行为:
- 多个任务使用同一个 ThreadID
- 当ThreadID X的第一个任务N结束时,调用RunWorkerCompleted delegate,并刷新其日志+仅ThreadID X的下一个任务N+1的一部分(因为任务还没有结束) )
- 当N+1任务真正结束时,将剩余的日志刷新写入,但是日志文件因为不整齐,乱七八糟!
我知道托管线程 ID 可能会被回收和重用,但我认为发生这种情况的唯一方法是当 BackgroundWorker 运行 还没有调用 RunWorkerCompleted
我说得对吗?这种情况有什么不明白的地方吗?
也许在那种情况下使用 ManagedThreadId 作为字典的键是一种不好的做法?
感谢您的帮助:)
我发现了我的问题:在FlushWrite
操作期间,执行了一个锁。如果一个worker等待时间过长,另一个worker可以写入同一个ThreadID,导致本例flush操作不一致。
通过使用另一个字典解决,仅用于冲洗“完全工人”。
代码也已重写,将 BackGroundWorker
更改为 Task.Run
。谢谢:)