我有一些计算程序。现在,这个程序是单线程的,我需要增强它来做多线程。一般来说,程序计算,热电路的动态演化(一些配置类型的不同涉及元素(管,泵,活动区及其连接),每个时间步程序计算扩散方程(http://en.wikipedia.org/wiki/Diffusion_equation )) 问题是,在每个步骤中,每个涉及的元素都可以单独处理,但是在每个新的时间步骤中,所有元素应该彼此同步。 我已经决定通过每个元素的每个时间步骤开始一个元素来解决它。
private void SolveElementDynamic(object element)
{
if (element is PJunction)
{
((PJunction)element).SolveDynamic();
}
else
if (element is PElementData)
{
((PElementData)element).SolveDynamic();
}
}
public void SolveDynamic()
{
ParameterizedThreadStart threadStart = new ParameterizedThreadStart(SolveElementDynamic);
for (int i = 0; i < _elementDataCollection.Count; i++)
{
_threadArray.Add(new Thread(threadStart));
}
int j = 0;
foreach (object element in _elementDataCollection)
{
((Thread)_threadArray[j]).Start(element);
j++;
}
}
但似乎与每步计算一个元素相比,创建新线程太昂贵了。我试图在计算开始时只创建一次Thread数组。但不幸的是,似乎Thread对象不能启动多次?
// Thread's array created before
public void SolveDynamic()
{
int j = 0;
foreach (object element in _elementDataCollection)
{
((Thread)_threadArray[j]).Start(element);
j++;
}
}
有什么办法吗?或者有没有办法做得更好?)
PS我从未在.Net中遇到线程,我在线程编程方面有一些小练习
答案 0 :(得分:7)
答案 1 :(得分:1)
首先,为什么你的解决方案不起作用:
.NET线程与OS对象(os线程)相关联 - 而windows(以及unix)也包含自己的执行堆栈。现在,如果你在哪里有多个执行单元使用相同的堆栈,它将导致绝对不可预测的行为。 因此:一个线程对象只能运行或不运行 - 不像运行10次。
可以使用线程数组 - 但是您需要为每个索引创建一个新的线程元素。
在计算的每个步骤中使用新线程的问题在于线程本身的创建成本相当高 - 它需要进行系统调用,创建堆栈,内核对象等等。
您可能希望做两件事:
首先,为每个线程分配不止一个步骤。更有效的一个版本是拥有一个中央(同步)工作队列,每个线程可以获得更多工作。然后,您只为每个可用的CPU创建一个单独的线程,并且通常一次分配多个工作步骤(否则您的瓶颈将是工作分配)。
其次,重用现有的线程。无论是使用.NET线程池,还是简单地不重新创建线程,在这种情况下都无关紧要 - 现有线程的同步比完全重新创建便宜很多。此外,如果你使用超薄锁,你可以完全避免操作系统。
答案 2 :(得分:1)
为什么你需要你的程序是多线程的?它会让你的程序变得更复杂,那么你希望的好处是什么?您想利用更多内核来提高速度吗?
假设您想要使用更多内核,您可能需要查看.NET 4和Parallel Programming。
它目前仍处于测试版状态,但看起来非常稳定,很快就会发布。
答案 3 :(得分:1)
由于C#中的并列性经验有限,我建议您查看PLINQ及其构建的任务并行库。该框架目前是.Net 3.0独立“附加”库的一部分,但将内置于.Net 4.0框架中。
您可以使用Task构造或并行For扩展方法执行您当前尝试执行的操作:
foreach (var element in var _elementDataCollection)
{
var task = new Task(element.SolveDynamic);
task.Wait();
}
或
Parallel.ForEach(_elementDataCollection, x => {
x.SolveDynamic();
});