【发布时间】:2015-03-02 22:25:30
【问题描述】:
这是一个看似简单的类,用于对数组中的所有元素求和:
class ArraySum
{
class SumRange
{
int left;
int right;
int[] arr;
public int Answer { get; private set; }
public SumRange(int[] a, int l, int r)
{
left = l;
right = r;
arr = a;
Answer = 0;
}
public void Run()
{
if (right - left == 1)
{
Answer = arr[left];
}
else
{
SumRange leftRange = new SumRange(arr, left, (left + right) / 2);
SumRange rightRange = new SumRange(arr, (left + right) / 2, right);
Thread leftThread = new Thread(leftRange.Run);
Thread rightThread = new Thread(rightRange.Run);
leftThread.Start();
rightThread.Start();
leftThread.Join();
rightThread.Join();
Answer = leftRange.Answer + rightRange.Answer;
}
}
}
public static int Sum(int[] arr)
{
SumRange s = new SumRange(arr, 0, arr.Length);
s.Run();
return s.Answer;
}
}
当然,这不是执行此任务的有效方式。这也是线程的非常低效的使用。编写本课程是为了说明一个基本的分而治之的解决方案概念,并且希望能够做到这一点。
这里也是这个类的一个简单的单元测试:
public void should_calculate_array_sum()
{
int N = 1000;
int[] arr = System.Linq.Enumerable.Range(0, N).ToArray();
int sum = ArraySum.Sum(arr);
Assert.AreEqual(arr.Sum(), sum);
}
这就是问题所在。当 N 设置为 1000 时,此测试在我的机器上失败了大约 5 次(共 5 次),实际结果小于预期。当 N 为 100 及以下时 - 它永远不会失败,或者至少我从未见过它失败。
为什么这个程序会失败?这显然是一种非常低效的方法,线程管理的开销太大,但至少它应该总是正常工作,对吧?要么有一些我看不到的细微错误,要么有一些我不理解的线程概念。
另外,我不是在寻找更好的方法来解决这个特定的问题,也不是在寻找更好的方法来说明相同的概念。我只是想弄清楚为什么这种特殊方法有时会失败。
【问题讨论】:
-
注意:好问题,重现失败的测试。使用多线程完成的计算确实更小并且不遵循模式(pastebin.com/XscPFZYA)
-
您写到至少它应该产生正确的结果,但是您的程序创建了太多线程。您应该更早地考虑不分区,而不是以递归方式创建线程。
-
您正在创建数百个线程,所有线程都带有编组给它们的数组副本。您可能内存不足。更小的数组 = 足够的内存不会死。
-
@dotnetstep,对,我知道在一定的递归深度切换到非线程方法会成功。问题是 - 为什么它不能像现在这样产生正确的答案。
-
@Tim,从未出现内存不足异常。不是所有线程都共享对数组的相同引用吗?
标签: c# multithreading