.NET 3.5 上的并行 - 线程未完成嵌套 For 中的任务
我不久前在 DevLabs 上下载了 Parallel Extensions for .NET 3.5 SP1 并开始使用它。一切似乎都工作正常,直到我注意到日志中的一些异常,我很难理解它们为什么会发生。
下面是并行任务的一个片段:
Parallel.ForEach(myJobArray, currentJob =>
{
JobElements myJobElements = GetJobElements(currentJob);
Parallel.For(0, myJobElements.Length, (currentIndex, loopState) =>
{
if (MyFunction(param1, myJobElements[currentIndex]))
{
loopState.Stop();
}
}
);
}
);
这是 MyFunction 的伪代码:
private bool MyFunction(MyObject1 param1, MyObject2 param2)
{
log(string.Format("start SubFunction1() from thread {0}", Thread.CurrentThread.ManagedThreadId));
SubFunction1(); //which uses System.Diagnostics.Process to start a batch file (.bat) to execute a Perl script. If successful, a file will be generated.
log(string.Format("end SubFunction1() from thread {0}", Thread.CurrentThread.ManagedThreadId));
log(string.Format("start SubFunction2() from thread {0}", Thread.CurrentThread.ManagedThreadId));
SubFunction2(); //which again, uses System.Diagnostics.Process to start another batch file (.bat) to execute a Perl script which transforms the file from step #1 to a new file.
log(string.Format("end SubFunction2() from thread {0}", Thread.CurrentThread.ManagedThreadId));
}
日志显示一个线程启动了 SubFunction1() 但从未完成;即,没有日志条目显示具有相同线程 ID 的“end SubFunction1()”之类的内容。实际上,同一个线程似乎继续执行数组中的下一个作业并再次调用 SubFunction1()。当另一个线程试图代替前一个线程启动 SubFunction2() 并且找不到从 SubFunction1() 生成的文件时,就会发生异常。
我认为每个线程都保证从头到尾完成其任务,但我不明白为什么日志会这样显示。我还应该补充一点,行为并不一致;即,大多数情况下程序运行时没有异常,但有时会由于上述问题而引发异常。
有什么想法吗?
I downloaded Parallel Extensions for .NET 3.5 SP1 on DevLabs a while ago and started using it. Everything seemed to work fine until I noticed some exceptions in the logs which I have a hard time to understand why they happened.
Here's a snippet of the parallel task:
Parallel.ForEach(myJobArray, currentJob =>
{
JobElements myJobElements = GetJobElements(currentJob);
Parallel.For(0, myJobElements.Length, (currentIndex, loopState) =>
{
if (MyFunction(param1, myJobElements[currentIndex]))
{
loopState.Stop();
}
}
);
}
);
Here's the pseudo code of MyFunction:
private bool MyFunction(MyObject1 param1, MyObject2 param2)
{
log(string.Format("start SubFunction1() from thread {0}", Thread.CurrentThread.ManagedThreadId));
SubFunction1(); //which uses System.Diagnostics.Process to start a batch file (.bat) to execute a Perl script. If successful, a file will be generated.
log(string.Format("end SubFunction1() from thread {0}", Thread.CurrentThread.ManagedThreadId));
log(string.Format("start SubFunction2() from thread {0}", Thread.CurrentThread.ManagedThreadId));
SubFunction2(); //which again, uses System.Diagnostics.Process to start another batch file (.bat) to execute a Perl script which transforms the file from step #1 to a new file.
log(string.Format("end SubFunction2() from thread {0}", Thread.CurrentThread.ManagedThreadId));
}
The logs showed that one thread started SubFunction1() but never finished; i.e., there was no log entry saying something like "end SubFunction1()" with the same thread ID. Actually, the same thread seemed to move on to the next job in the array and call SubFunction1() again. The exception happened when another thread tried to stand in for the previous thread to start SubFunction2() and couldn't find the file generated from SubFunction1().
I thought each thread was guaranteed to finish its tasks from start to finish and I can't figure out why the logs show this way. I should also add that the behavior is not consistent; i.e., most of the time the program runs with no exceptions but sometimes it throws exceptions due to the aforemention problems.
Any thoughts?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果
SubFunction1()
抛出异常,则不会发生这种情况。This will not happen if
SubFunction1()
throws an exception.首先,不能保证,因为您正在使用
loopState.Stop();
并且从您的代码中不清楚如何、何时以及什么MyFunction()
返回。然后,执行任务/线程的内容和写入日志(文件)的内容是两个不同的事情,很可能无法相互反映:
log(string.Format("end SubFunction1() from thread {0}", Thread.CurrentThread.ManagedThreadId));
不会显示实际任务的线程 ID(但显示日志的线程)。如果它确实显示实际任务的线程ID,那么不清楚(从您的代码中)为什么您没有通过从多个线程写入日志来获得跨线程异常您应该通过以下任一方式同步日志记录:
First, it is not guaranteed since you are using
loopState.Stop();
and it is not clear from your code how, when and whatMyFunction()
returns.Then, what is doing tasks/threads and what is written to a log (file) are two different things, more than probably not reflecting each other:
log(string.Format("end SubFunction1() from thread {0}", Thread.CurrentThread.ManagedThreadId));
does not show the actual task's thread ID (but log's thread). If it does show actual task's thread ID, then it is not clear (from your code) why you doesn't get cross-thread exception by writing to log from multiple threadsYou should have synchronized the logging by either:
Parallel.For
loop flushing output stream at the end of each loop to protect acceess to log