我是并行编程的新手,我不确定为什么QuickSortParallel
方法比我的顺序版本慢(没有Parallel.Invoke)。我有一个锯齿状的数组,由我传递的十万个9位数字组成。不幸的是,当我使用QuickSortParallel
方法时,它最终比顺序版本慢近5倍。
我可以做的不仅仅是在数据源上使用Parallel.Invoke吗?
public static void QuickSort_Parallel<T>(T[] array2) where T : IComparable<T>
{
QuickSortParallel(array2, 0, array2.Length - 1);
}
private static void QuickSortParallel<T>(T[] array2, int left, int right)
where T : IComparable<T>
{
if (left >= right)
{
return;
}
SwapElements(array2, left, (left + right) / 2); //median pivot
int last = left;
for (int current = left + 1; current <= right; ++current)
{
//CompareTo, compares current array index value with
if (array2[current].CompareTo(array2[left]) < 0)
{
++last;
SwapElements(array2, last, current);
}
}
SwapElements(array2, left, last);
//Recursive
//Executes each of the provided actions in parallel.
Parallel.Invoke(
() => QuickSortParallel(array2, left, last - 1),
() => QuickSortParallel(array2, last + 1, right)
);
}
static void SwapElements<T>(T[] array2, int i, int j)
{
T temp = array2[i];
array2[i] = array2[j];
array2[j] = temp;
}
答案 0 :(得分:2)
很可能,你的问题来自于线程的开销。
使用线程通常会使CPU密集型工作更快,但是启动一个新线程需要大量开销,如果你给太多线程太少工作,那么你可以让你的程序运行得更慢。
运行以下行时:
Parallel.Invoke(
() => QuickSortParallel(array2, left, last - 1),
() => QuickSortParallel(array2, last + 1, right)
);
...您可能导致当前线程产生另外两个线程(取决于Parallel.Invoke
的实现方式)。如果我的心理数学是正确的(如果Parallel.Invoke
确实创建了新的线程),那么你正在创建n * log(n)
个线程 - 这是一个巨大的数字!
如果你想看到性能提升,你需要平衡线程数 - 更多并不总是更好。使用系统线程池限制线程数的好方法:
System.Threading.ThreadPool.QueueUserWorkItem(
() => QuickSortParallel(array2, left, last - 1));
System.Threading.ThreadPool.QueueUserWorkItem(
() => QuickSortParallel(array2, last + 1, right));
......或者其他类似的东西。如果您愿意,也可以实现自己的线程池。 一个
另一种选择是限制递归的深度,从而限制线程的数量。
答案 1 :(得分:2)
所有这些递归调用都会杀了你。本文http://reedcopsey.com/2010/02/26/parallelism-in-net-part-11-divide-and-conquer-via-parallel-invoke/非常相关。
答案 2 :(得分:0)
围绕使用SwapElements方法的争论?尝试将SwapElements方法的逻辑直接放入方法/循环中,而不是调用它...这将允许它成为生成的每个并行线程上发生的事情的一部分,而不是潜在的瓶颈。看看那是不是什么......只是一个建议,但不确定它是否会证明是有用的。